【juc】wait和notify原理

文章详细介绍了Java中的Monitor锁结构,包括waitset和entrylist的概念,以及wait、notify和notifyAll方法的原理和使用。在synchronized块中,线程调用wait会释放锁进入等待,而notify和notifyAll会唤醒等待的线程,这些线程需要重新竞争锁。示例代码展示了wait方法的使用限制和时间参数的影响,以及notify和notifyAll唤醒线程的不同行为。

一、monitor锁结构图

在这里插入图片描述

二、原理说明
  • 1.线程1一开始持有对象A的monitor锁,即monitor中的owner指向线程1
  • 2.线程1在执行的过程中发现条件a不满足执行不下去了,此时线程1可以调用wait方法,那么线程1就进入waitset进行等待,状态为waiting
  • 3.线程4准备给对象A加锁,发现当前对象A的monitor的owner是线程2,线程4则会进入entryList中准备竞争
  • 4.waitset和entrylist中的线程都处于阻塞状态,不会占用cpu的时间片
  • 5.waitset中的线程是获取到了锁,但又主动放弃了锁;entrylist中的线程是准备加锁时发现锁已经被其它线程占用,而获取不到锁
  • 6.waitset中的线程1和线程3会在owner指向的线程1调用notify或者notifyAll时唤醒,被唤醒后,不会立刻获得锁,还是要进入entrylist等待下一次竞争
三、api说明
  • 1.obj.wait():synchronized(obj){代码块},代码块wait方法让进入obj监视器的线程到monitor的waitset中等待
  • 2.obj.notify()在obj的monitor的waitset中等待的线程中挑一个唤醒
  • 3.obj.notifyAll()在obj的monitor的waitset中等待的所有线程全部唤醒
  • 4.wait、notify、notifyAll方法都是在线程之间进行协作的手段,都属于Object对象的方法,必须获得此对象的锁才能调用这几个方法
四、api使用
4.1 wait方法
  • 1.wait方法需要放synchronized代码块里,否则运行会报IllegalMonitorStateException异常
  • 2.对象执行wait方法后,该线程会进入阻塞,其它线程可以竞争到对象的monitor
package com.learning.wait;

/**
 * @Author wangyouhui
 * @Description 对象的wait方法必须放synchronized代码块里
 **/
public class WaitLearning {
    static final Object lock = new Object();
    public static void main(String[] args) {
        try {
            lock.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Exception in thread "main" java.lang.IllegalMonitorStateException
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:502)
	at com.learning.wait.WaitLearning.main(WaitLearning.java:11)
  • 3.在synchronized代码块中执行等待,获得锁的主线程一直在等待,阻塞中
package com.learning.wait;

/**
 * @Author wangyouhui
 * @Description 对象的wait方法必须放synchronized代码块里
 **/
public class WaitLearning {
    static final Object lock = new Object();
    public static void main(String[] args) {
        synchronized (lock) {
            try {
                lock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 4.wait(时间),当超过等待时间会自动唤醒
package com.learning.wait;

import lombok.extern.slf4j.Slf4j;

/**
 * @Author wangyouhui
 * @Description 对象的wait时间方法,当时间过去后,会继续执行
 **/
@Slf4j
public class WaitTimeLearning {
    static final Object lock = new Object();
    public static void main(String[] args) {
        new Thread(()->{
            synchronized (lock) {
                try {
                    log.info("线程1等待");
                    lock.wait(2000);
                    log.info("线程1继续执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "thread1").start();
    }
}

在这里插入图片描述

  • 5.wait(时间),等待时间内被其它线程唤醒会提前唤醒
package com.learning.wait;

import lombok.extern.slf4j.Slf4j;

/**
 * @Author wangyouhui
 * @Description 对象的wait时间方法,当时间过去后,会继续执行
 **/
@Slf4j
public class WaitTimeLearning2 {
    static final Object lock = new Object();
    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            synchronized (lock) {
                try {
                    log.info("线程1等待");
                    lock.wait(2000);
                    log.info("线程1继续执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "thread1").start();

        Thread.sleep(1000);

        synchronized (lock){
            log.info("主线程唤醒");
            lock.notify();
        }
    }
}

在这里插入图片描述

4.2 notify方法
  • 1.notify方法需要放在synchronized代码块中,notify方法只能唤醒waitset中的一个线程
package com.learning.notify;

import lombok.extern.slf4j.Slf4j;


/**
 * @Author wangyouhui
 * @Description notify方法从waitset中挑选一个等待的线程唤醒
 **/
@Slf4j
public class NotifyLearning {
    static final Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            synchronized (lock){
                log.info("线程1等待");
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("线程1继续执行");
            }
        }, "thread1").start();
        new Thread(()->{
            synchronized (lock){
                log.info("线程2等待");
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("线程2继续执行");
            }
        }, "thread2").start();

        Thread.sleep(2000);
        synchronized (lock){
            log.info("主线程拿到锁,执行lock.notify方法,唤醒waitset中的一个线程");
            lock.notify();
        }
    }
}

 [thread1] INFO com.learning.notify.NotifyLearning - 线程1等待
 [thread2] INFO com.learning.notify.NotifyLearning - 线程2等待
 [main] INFO com.learning.notify.NotifyLearning - 主线程拿到锁,执行lock.notify方法,唤醒waitset中的一个线程
 [thread1] INFO com.learning.notify.NotifyLearning - 线程1继续执行
4.3 notifyAll方法
  • 1.notifyAll方法将waitset中所有等待的线程都唤醒
package com.learning.notifyall;
import lombok.extern.slf4j.Slf4j;
/**
 * @Author wangyouhui
 * @Description notifyAll方法将waitset中所有等待的线程都唤醒
 **/
@Slf4j
public class NotifyAllLearning {
    static final Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            synchronized (lock){
                log.info("线程1等待");
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("线程1继续执行");
            }
        }, "thread1").start();
        new Thread(()->{
            synchronized (lock){
                log.info("线程2等待");
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("线程2继续执行");
            }
        }, "thread2").start();

        Thread.sleep(2000);
        synchronized (lock){
            log.info("主线程拿到锁,执行lock.notify方法,唤醒waitset中的一个线程");
            lock.notifyAll();
        }
    }
}

[thread1] INFO com.learning.notifyall.NotifyAllLearning - 线程1等待
[thread2] INFO com.learning.notifyall.NotifyAllLearning - 线程2等待
[main] INFO com.learning.notifyall.NotifyAllLearning - 主线程拿到锁,执行lock.notify方法,唤醒waitset中的一个线程
 [thread2] INFO com.learning.notifyall.NotifyAllLearning - 线程2继续执行
[thread1] INFO com.learning.notifyall.NotifyAllLearning - 线程1继续执行
内容概要:本文档是一份关于交换路由配置的学习笔记,系统地介绍了网络设备的远程管理、交换机与路由器的核心配置技术。内容涵盖Telnet、SSH、Console三种远程控制方式的配置方法;详细讲解了VLAN划分原理及Access、Trunk、Hybrid端口的工作机制,以及端口镜像、端口汇聚、端口隔离等交换技术;深入解析了STP、MSTP、RSTP生成树协议的作用与配置步骤;在路由部分,涵盖了IP地址配置、DHCP服务部署(接口池与全局池)、NAT转换(静态与动态)、静态路由、RIP与OSPF动态路由协议的配置,并介绍了策略路由ACL访问控制列表的应用;最后简要说明了华为防火墙的安全区域划分与基本安全策略配置。; 适合人群:具备一定网络基础知识,从事网络工程、运维或相关技术岗位1-3年的技术人员,以及准备参加HCIA/CCNA等认证考试的学习者。; 使用场景及目标:①掌握企业网络中常见的交换与路由配置技能,提升实际操作能力;②理解VLAN、STP、OSPF、NAT、ACL等核心技术原理并能独立完成中小型网络搭建与调试;③通过命令示例熟悉华为设备CLI配置逻辑,为项目实施故障排查提供参考。; 阅读建议:此笔记以实用配置为主,建议结合模拟器(如eNSP或Packet Tracer)动手实践每一条命令,对照拓扑理解数据流向,重点关注VLAN间通信、路由选择机制、安全策略控制等关键环节,并注意不同设备型号间的命令差异。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王佑辉

老板,赏点吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值