Java多线程synchronized、wait和notify问题

废话不多说,直接粘测试代码


public class Test{
    public static void main(String[] args) {
        try {
            ThreadB tb = new ThreadB();
            tb.start();
            System.out.println("0");
            synchronized (tb) {
                System.out.println("3");
                tb.wait();
                System.out.println("4");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class ThreadB extends Thread {

    @Override
    public void run() {
        synchronized (this) {
            System.out.println("1");
            notify();
            System.out.println("2");
        }
    }

}

为什么输出结果
有时候是:
0
1
2
3
有时候是:
0
1
2
3
4

public class Test{ public static void main(String[] args) { try { ThreadB tb =...

其实你还少说了一种可能,即:0,3,1,2,4.
对于0,1,2,3来说,首先main线程输出0没有疑问,接下来tb获得对象自身的锁,而main线程在竞争tb对象自身的锁时失败处于阻塞状态,因此执行tb线程的run方法,输出1,调用notify方法,输出2,释放自身对象锁,main线程获得tb对象锁,输出3,调用wait方法,此时存在两种情况:
若nitify方法通知过早,则main线程一直处于wait状态,整个程序不会结束,整个输出为0,1,2,3
若notify方法在main线程调用wait方法之后到达,则输出4,main线程释放对象锁,主程序结束,输出为:0,1,2,3,4
若main线程先获取到tb对象锁,输出3,之后处于wait状态,释放tb对象锁,此时tb线程获取对象锁,输出2,调用notify通知处于wait状态的main线程,输出3之后释放对象锁,此后main得到对象锁,执行wait之后的语句,输出4,
整个输出为0,3,1,2,4.

同意这个说法,其实你还少说了一种可能,即:0,3,1,2,4.
对于0,1,2,3来说,首先main线程输出0没有疑问,接下来tb获得对象自身的锁,而main线程在竞争tb对象自身的锁时失败处于阻塞状态,因此执行tb线程的run方法,输出1,调用notify方法,输出2,释放自身对象锁,main线程获得tb对象锁,输出3,调用wait方法,此时存在两种情况:
若nitify方法通知过早,则main线程一直处于wait状态,整个程序不会结束,整个输出为0,1,2,3
若notify方法在main线程调用wait方法之后到达,则输出4,main线程释放对象锁,主程序结束,输出为:0,1,2,3,4
若main线程先获取到tb对象锁,输出3,之后处于wait状态,释放tb对象锁,此时tb线程获取对象锁,输出2,调用notify通知处于wait状态的main线程,输出3之后释放对象锁,此后main得到对象锁,执行wait之后的语句,输出4,
整个输出为0,3,1,2,4.

只有在wait命令执行在notify前面才会出现0 1 2 3 4

我感觉是一个bug啊,

 package test;

public class Test { 
    public static final Object lock = new Object();
    public static ThreadB lock2;
    public static void main(String[] args){
         try {
                lock2 = new ThreadB();
                lock2.start();
                System.out.println("0");
                synchronized (lock) {
                    System.out.println("3");
                    lock.wait();
                    System.out.println("4");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }

}
class ThreadB extends Thread {

    @Override
    public void run() {
        synchronized (Test.lock) {
            System.out.println("1");
            Test.lock.notify();
            System.out.println("2");
        }
    }
}

这个代码将互斥量改成lock 就会错失notify信息,符合我的想法。
如果将互斥量改成线程本身lock2,wait和notify就好像失效了一样,很神奇、、、我也不知道为什么

刚看了一下JDK中关于Object对象wait和notify方法的描述,找到如下语句:
图片说明
代码修改如下:


public class Test{
    public static void main(String[] args) {
        try {
            ThreadB tb = new ThreadB();
            tb.start();
            System.out.println("0");
            synchronized (tb) {
                System.out.println("3");
                while(true) {
                    System.out.println("4");
                    tb.wait();
                    System.out.println("虚假唤醒情况");
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

ThreadB类保持不变

我感觉一个线程消亡后,会自动调用该线程的notify(),我猜的

 package test;

public class Test { 
    public static void main(String[] args){
        try {
            ThreadB tb = new ThreadB();
            tb.start();
            System.out.println("0");
            synchronized (tb) {
                System.out.println("3");
                tb.wait();
                System.out.println("4");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class ThreadB extends Thread {
    @Override
    public void run() {
        System.out.println("1");
        System.out.println("2");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

你这代码不知道要干啥,完全没有同步和互斥的作用。你是想打印出1 2 3 4吗?