java基础-线程状态分析-wait、notify分析

100 阅读1分钟

java基础-线程状态分析中,我们讲述了线程的状态转换,本节分析wait、notify的原理。 先来一个使用wait、notify,三个线程打印1-99的数字,每个线程打印33个数字

public class OldEven {
    private static int cnt = 1;

    public static void main(String[] args) {
        Object object = new Object();

        //打印0
        new Thread(() -> {
            while (cnt <= 99) {
                //1. notifyall使用后,其他俩线程都会执行到这里,所以步骤2增加cnt<=99判断
                //同步操作,其实是获取object的监视器,java每个对象都有监视器
                synchronized (object) {
                    //2. 此处再次判断cnt <= 99 ,防止在打印99的时候,另外两个线程一个打印99,另一个打印100
                    if (cnt <= 99 && cnt % 3 == 0) {
                        System.out.println(Thread.currentThread().getName() + "打印数字:" + (cnt++));
                        //本线程打印完后,通知其他线程进行打印
                        //notify执行后不会里面释放对象监视器(锁),需要将synchronized代码块执行完,除非手动执行wait
                        object.notifyAll();
                        //此处加个判断,防止超过99后,wait的线程没其他线程唤醒
                        if (cnt <= 99) {
                            try {
                                //执行wait,手动释放监视器(锁),并将当前线程进行waiting状态,线程进入监视器队列
                                object.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }

                }
            }
            System.out.println(Thread.currentThread().getName() + "打印数字结束");
        }).start();

        //打印1
        new Thread(() -> {
            while (cnt <= 99) {
                synchronized (object) {
                    if (cnt <= 99 && cnt % 3 == 1) {
                        System.out.println(Thread.currentThread().getName() + "打印数字:" + (cnt++));
                        object.notifyAll();
                        if (cnt <= 99) {
                            try {
                                object.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }

                }
            }
            System.out.println(Thread.currentThread().getName() + "打印数字结束");
        }).start();

        //打印2
        new Thread(() -> {
            while (cnt <= 99) {

                synchronized (object) {
                    if (cnt <= 99 && cnt % 3 == 2) {
                        System.out.println(Thread.currentThread().getName() + "打印数字:" + (cnt++));
                        object.notifyAll();
                        if (cnt <= 99) {
                            try {
                                object.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }

                }
            }
            System.out.println(Thread.currentThread().getName() + "打印数字结束");
        }).start();
    }
}

image.png

Object的wait.notify的本地方法,cpp代码也很复杂,整体逻辑如下图所示

当使用synchronized的时候,这样的代码块,编译后会生成monitorenter和monitorexit指令,线程执行到monitorenter指令时会尝试取得lock对应的monitor的所有权(CAS设置对象头),取得后即获取到锁,执行monitorexit指令(执行notify)时会释放monitor的所有权即释放锁

image.png