Synchronized 重量锁的数据结构以及Wait和notify的使用

一、重量锁的数据结构
     1、 Synchronized升级到重量锁以后,会创建一个ObjectMonitor对象,对象中会有:当前持有锁的线程、WaitSet(保存处于Waiting状态的线程)、EntryList(保存处于Blocked状态的线程)
     2、重量锁本质:重量锁使用操作系统底层的 Mutex Lock
     3、ObjectMonitor作用:那在升级重量所过程中创建ObjectMonitor是用来对 资源竞争激烈的线程的进行统一管理的一种数据结构
     4、ObjectMonitor结构图:
      
二、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测试案例
   说明线程唤醒后还是需要获取锁才能执行
   
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();


    }
}
View Code
 
 
原文地址:https://www.cnblogs.com/lean-blog/p/13719493.html