多线程中的wait和notify

1、wait和notify

由于线程之间是抢占式执行的,所以线程之间的执行先后顺序难以预知。但实际上是希望合理的协调多个线程之间的执行先后顺序。

 完成这个协调工作,主要涉及到三个方法

*wait()/wait(long timeout);让当前线程进入等待状态。

*notify()/notifyAll();唤醒在当前对象上等待的线程。

注意:wait,notify,notifyAll都是Object的方法,而之前提到的join()(等待当前线程运行结束)方法是Thread类中的方法,

2、wait方法

wait做的事情:

*使当前执行的代码的线程进行等待。(把线程放到等待队列中) 

*释放当前锁

*满足一定条件就会被唤醒,重新尝试获取这个锁。

wait要搭配synchronized一起使用,脱离synchronized使用wait就会抛出异常。

wait结束等待的条件:

*其他线程调用该对象的notify()方法

*wait等待时间超时(wait提供一个带有timeout参数的版本,来指定等待时间)

*其他线程调用该等待线程的interrupted方法,导致wait抛出InterrputedException异常。

3、 notify方法

notify是唤醒等待线程的方法

*方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其他线程,对其发出通知notify(),并使它们重新获取该对象的对象锁。

*如果有多个线程等待,则有线程调度器随机挑选一个状态为wait的线程,(并没有“先来后到的原则”)。

*在notify()方法后,当前线程不会马上释放该对象锁,要等待到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。

4、代码示例:

/**
 * wait()和notify()方法
 */
public class Exe_02 {
    public static void main(String[] args) {
        //定义一个锁对象
        Object locker=new Object();
        //创建调用wait()方法的线程
        Thread t1=new Thread(() ->{
            while(true){
                System.out.println("wait之前");
                try {
                    synchronized (locker) {
                        locker.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("wait之后");
                System.out.println("==============");
            }
        },"t1");
        //创建调用notify方法线程
        Thread t2=new Thread(() ->{
            while(true){
                System.out.println("notify之前");
                //加入锁
                synchronized (locker) {
                    locker.notify();
                }
                System.out.println("notify之后");
                //休眠一会
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t2");
        //启动线程
        t1.start();
        t2.start();
    }
}

 执行逻辑分析:

 注意:

1、当一个线程调用了wait()之后,就释放掉当前持有的锁,等待被其他线程唤醒。

2、当另一个线程调用了notify()之后, 之前调用wait()的线程被唤醒后,需要重新竞争锁资源然后再从之前wait的位置向下执行自己的逻辑。

4.1、notify()和notifyAll()

notify方法只是随机唤醒某一个线程,这个线程来获取锁;

notifyAll可以一次性唤醒所有等待的线程,这些线程全部去竞争锁,谁先拿到谁先处理。 

 5、观察多线程环境下锁状态

代码示例:

import org.openjdk.jol.info.ClassLayout;

public class Exe_03 {
    //定义一些变量
    private int count;
    private long count1=200;
    private String hello="";
    //定义一个对象变量
    private textExe_03 text03=new textExe_03();

    public static void main(String[] args) throws InterruptedException {
        //创建一个对象的实例
        Object obj=new Object();
        //打印实例布局
        System.out.println("=====任意object对象布局,起初无锁状态");
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());
        System.out.println("延迟三秒开启偏向锁");
        //延迟3秒开启偏向锁
        Thread.sleep(3000);
        //创建本类的实例
        Exe_03 exe_03=new Exe_03();
        //打印实例布局,查看锁状态
        System.out.println("=====打印实例布局,查看锁状态");
        System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
        //调用hashCode后,保存hashCode的值
        exe_03.hashCode();
        //观察现象
        System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
        System.out.println("==============================");
        System.out.println("synchronized加锁");
        //加锁后观察锁信息
        synchronized(exe_03){
            System.out.println("第一层synchronized加锁后");
            System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
            //锁重入,观察锁信息
            synchronized(exe_03){
                System.out.println("第二层synchronized加锁后");
                System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
            }
            //释放里层的锁
            System.out.println("释放内层锁后");
            System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
        }
        //释放所有锁之后
        System.out.println("=========释放所有锁========");
        System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
        System.out.println("==============================");
        //强制执行垃圾回收
        System.gc();
        //观察GC计数
        System.out.println("+++++++调用GC后查看age的值");
        System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
        //打印类布局,调用不同的方法查看
        System.out.println("+++++查看类布局");
        System.out.println(ClassLayout.parseClass(Exe_03.class).toPrintable());
        //打印类对象布局
        System.out.println("+++++查看类对象布局");
        System.out.println(ClassLayout.parseInstance(Exe_03.class).toPrintable());
        synchronized (Exe_03.class){
            //加锁后的类对象
            System.out.println("+++++对类对象加锁后,不同的对象获取锁,观察锁升级为thin lock");
            System.out.println(ClassLayout.parseInstance(Exe_03.class).toPrintable());
        }
        //释放锁之后的类对象
        System.out.println("+++++释放锁后");
        System.out.println(ClassLayout.parseInstance(Exe_03.class).toPrintable());
        System.out.println("+++++多个锁线程参与锁竞争,观察锁状态+++++");
        Thread t1=new Thread(() ->{
            synchronized(exe_03){
                System.out.println("++++++在线程A中参与锁竞争,观察锁状态++++++");
                System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
            }
        });
        t1.start();
        Thread t2=new Thread(() ->{
            synchronized(exe_03){
                System.out.println("++++++在线程B中参与锁竞争,观察锁状态++++++");
                System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
            }
        });
        t2.start();
        Thread t3=new Thread(() ->{
            synchronized(exe_03){
                System.out.println("++++++在线程C中参与锁竞争,观察锁状态++++++");
                System.out.println(ClassLayout.parseInstance(exe_03).toPrintable());
            }
        });
        t3.start();
    }
}
class textExe_03{

}

 查看运行结果:

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值