萌新问一个java多线程同步死锁的问题

下面这两段代码,一个实现Runnable接口,一个继承Thread类,前面的能正常交替输出
但是后面继承Thread的运行会死锁,没想明白为什么会死锁,求指教

public class Test3 {
       static  class MyRun implements Runnable {
            static int i = 0;
            @Override
            public synchronized  void run() {
                for (int j = 0; j < 10; j++) {
                    if(i%2==0)
                        System.out.println(Thread.currentThread().getName()+":A");
                    else
                        System.out.println(Thread.currentThread().getName()+":B");
                    i++;
                    this.notifyAll();
                    try {
                        if(i>=19)
                            Thread.sleep(10);
                        else
                            this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        public static void main(String[] args) {
            MyRun myRun = new MyRun();
            Thread a = new Thread(myRun);
            Thread b = new Thread(myRun);
            a.start();
            b.start();
        }
    }
public class Test3 {
       static  class MyRun extends Thread {
            static int i = 0;
            @Override
            public synchronized  void run() {
                for (int j = 0; j < 10; j++) {
                    if(i%2==0)
                        System.out.println(Thread.currentThread().getName()+":A");
                    else
                        System.out.println(Thread.currentThread().getName()+":B");
                    i++;
                    this.notifyAll();
                    try {
                        if(i>=19)
                            Thread.sleep(10);
                        else
                            this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        public static void main(String[] args) {
            MyRun m1 = new MyRun();
            MyRun m2 = new MyRun();
            m1.start();
            m2.start();
        }
    }

int i = 0;移到run方法中试试,去掉static

第一个例子是一把锁,一把锁的持有者是new MyRun一个实例,第一个等待锁唤醒,第二个会把第一个锁唤醒,因为是同一把锁。
第二个例子是两把锁,两把锁的持有者分别是两个new MyRun实例,两个线程独立的锁,所以都在等待,不会被唤醒

这个不是死锁,后面的代码两个线程使用的不是同一把锁,运行暂停是因为this.wait();让自己的线程一直wait,而没法唤醒。

用 this 作为锁是不行的,一旦调用 this 锁后,当前线程就挂起了,再也不会有其他线程能够唤醒它了。
解决办法,定义一个锁对象,由调用者传入,同步时用该锁。并发编程的相关经验,有需要可以看看这篇:并发编程入门指南
另外,我回答了很多类似的问题,近期最详细的一条,参考下这个:多线程编程 notify 不起作用的原因分析

修改代码为:

static  class MyRun extends Thread {
        private Object lock = null;

        public MyRun(Object lock){
            this.lock = lock;
        }

        static int i = 0;
        @Override
        public  void run() {
            synchronized (lock) {
                for (int j = 0; j < 10; j++) {
                    if(i%2==0)
                        System.out.println(Thread.currentThread().getName()+":A");
                    else
                        System.out.println(Thread.currentThread().getName()+":B");
                    i++;
                    lock.notifyAll();
                    try {
                        if(i>=19)
                            Thread.sleep(10);
                        else
                            lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

    public static void main(String[] args) {
        Object lock = new Object();
        MyRun m1 = new MyRun(lock);
        MyRun m2 = new MyRun(lock);
        m1.start();
        m2.start();
    }