Synchronized 重量锁的数据结构以及Wait和notify的使用
一、重量锁的数据结构
1、 Synchronized升级到重量锁以后,会创建一个ObjectMonitor对象,对象中会有:当前持有锁的线程、WaitSet(保存处于Waiting状态的线程)、EntryList(保存处于Blocked状态的线程)
2、重量锁本质:重量锁使用操作系统底层的 Mutex Lock
3、ObjectMonitor作用:那在升级重量所过程中创建ObjectMonitor是用来对 资源竞争激烈的线程的进行统一管理的一种数据结构
4、ObjectMonitor结构图:
![](https://img2020.cnblogs.com/blog/512833/202009/512833-20200923165215792-520681294.png)
二、ObjectMonitor集合说明
1 Blocked和Waiting状态的线程都处于阻塞状态,不占用CPU资源
2 Blocked状态的线程会在锁被释放的时候唤醒
3 Waiting状态的线程会在调用Notify或者NotifyAll时候唤醒,但唤醒后不会立即获得锁,仍然需要进入到EntrySet集合中竞争锁
三、锁对象的Wait,线程做了什么?
1 、持有锁的线程调用Wait,即可进入到WaitSet集合中
2、调用Wait方法的锁一定是重量级锁(因为只有重量级锁才有ObjectMonitor,才有集合放置等待的对象)
3、在“锁对象”(锁对象中含有ObjectMonitor的指针)上调用notify或者notifyAll,会到集合中唤醒相应的线程
四、Wait和Sleep的区别
相同:Wait和Sleep都可以使线程阻塞
不同:
1 Wait阻塞时候会释放锁,Sleep不会
2 Wait通过notiry唤醒,Sleep时间到了自己会唤醒
3 Wait是Object对象的方法,Sleep是Thread类的方法
4 Wait需要配合Synchronized使用,否则会有异常,Sleep不需要
五、Wait和Notify测试案例
说明线程唤醒后还是需要获取锁才能执行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.test.test1; import java.util.concurrent.atomic.AtomicBoolean; /** * 1 wait 和notify必须在synchroinzed中执行 * 2 wait状态线程唤醒后,需要获取锁才能继续执行(本例字中t2唤醒t1后如果不释放锁,则t1是不会执行的) */ public class Test6 { public static void main( String[] args ) throws InterruptedException { Thread t1=null; Thread t2 = null; Object lock = new Object(); AtomicBoolean haveMoney = new AtomicBoolean(true) ; //第一个线程 t1 ,只要有钱,则花钱,直到没有钱了则退出 t1 = new Thread(){ @Override public void run() { synchronized (lock){ while (haveMoney.get()){ try { System.out.println("花钱"); lock.wait(); System.out.println("线程1 被换醒了 "); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("终于把所有钱花完了 ,哈哈。。。。。"); } } }; //释放cpu资源,让t1 获取所并且wait Thread.sleep(1000); t2 = new Thread(()->{ synchronized (lock){ // 唤醒锁 中等待的线程 t1 System.out.println("线程3去唤醒t2了"); lock.notifyAll(); //测试 T2不释放锁的情况下 t1不执行的情况 // try { // // t2 睡眠10s中,让t1获取到锁,则t1会自旋执行 // Thread.sleep(10000); // } catch (InterruptedException e) { // e.printStackTrace(); // } // // //t2设置 t1标识为没钱,使t1循环结束,并唤醒t1 // System.out.println("设置线程t1状态为false=="+ haveMoney.get()); // haveMoney.set(false); // lock.notifyAll(); } try { // t2 睡眠10s中,让t1获取到锁,则t1会自旋执行 Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock){ //t2设置 t1标识为没钱,使t1循环结束,并唤醒t1 System.out.println("设置线程t1状态为false=="+ haveMoney.get()); haveMoney.set(false); lock.notifyAll(); } }); t1.setName("线程t1 "); t2.setName("线程t3 "); t1.start(); t2.start(); } }