Concurrent hero vs monster program
One major problem with this code that I can see is that you need to consider what you are synchronizing, and why. I understand your main objective here is learning concurrency but I've also added some other suggestions you may or may not want to use.

Concurrency

There are a couple of issues with the way you are synchronizing things. In your case, the things you'd want to prevent happening are:


Interleaving on the players' attacks. This might happen if two
separate threads try and damage the same enemy.
Preventing both the Hero and Monster 'winning' (killing each other). Note: you might not want to prevent this


The synchronized blocks will prevent any code with the same lock executing at the same time. Therefore you need to synchronize:


Modifications to health of self or enemy.
Checks of health of self or enemy.


You should not synchronize the Thread.sleep(); calls because each thread will have stop and wait for all the other ones to stop sleeping. So what does this look like for your code? Let's see:

public void hitHero() {
    boolean isFighting = true;
    while (isFighting) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (lock) {
            monster.attack(hero, random.nextInt(20));
            if (hero.getHp() &lt; 0) System.out.println("Monster won.");
            isFighting = hero.getHp() &gt; 0 &amp;&amp; monster.getHp() &gt; 0;
        }

    }
}


Note that I have used the boolean isFighting in order to move the checks to HP inside the synchronized block.

This solution will not prevent the two from killing each other if one dies while the other is waiting to attack. To prevent this, you'll need to add other checks inside the synchronized block.

Encapsulation

Consider the Monster and the Hero. They both share some common traits. They both have HP, a name, and can both attack something. Why not make a parent class (let's call it Fighter) that is not just an interface, but provides implementation for attack, and a hp + name:

public class Fighter {
    private int hp;
    private String name;

    public Fighter (int hp, String name) { ... }
    public int getHp() { ... }
    public String getName() { ... }
    public void decreaseHp(int dmg) { ... }

    public void attack(Fighter f, int dmg) {
        System.out.println(f.name + " hp: " + f.getHp());
        System.out.println(name + " dealt " + dmg + " damage");
        f.decreaseHp(dmg);
        System.out.println(f.name + " hp is now: " + f.getHp());
        System.out.println("--------------------------");
    }


The great thing about this is that you lose the need for the instanceof check, since you know you can attack any fighter you want. Now adding a new type of fighter is super easy:

public class Hero extends Fighter {   
    public Hero (int hp, String name) {
        super(hp, name);
    }
}


In addition to this, I would certainly consider making all the variables inside ThreadFight private, and creating + starting the two Threads inside ThreadFight's constructor (or inside a startFight() method).

Overall though, I think you've done a good job! You're running the threads correctly and nearly got the synchronization right. It can take a while to fully understand what's happening with multiple threads and locks. Though there are possible improvements the Monster and Hero were also built well. It's a nice little program and you could certainly expand upon it if you wanted to practice more complex threading situations.