我应该标记一下的java同步知识

本文主要介绍Java中synchronized和wait、notify、notifyAll的使用。synchronized使用方便但涉及知识点多,同一时刻只有一个线程能持有锁。wait、notify、notifyAll需在同步块中使用,它们使线程在WaitSet、EntryList和owner状态间转换。还提到应在循环中调用wait()以避免异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

synchronized

 synchronized使用起来非常的方便,但是方便不等于简单,里面涉及的知识点还是挺多的,这里简单记录一点笔记。

首先记录一下我所认识的锁,任何对象在头信息里都有一个锁标记,类也是特殊的对象(class对象),同一时刻只能有一个线程能持有这个锁,当用synchronized时,线程会获取锁,别的线程想要获取这个锁时只能等待这个线程释放锁。

这两天看了很多人的文章,讲的都大同小异,说到synchronized的用法,有的说三种,有的说四种,有的说五种,也不知道官方是怎么定义的,我就把所有的都罗列一下:

锁代码块synchronized(this)对象锁
synchronized(object)对象锁
synchronized(class)类锁
锁方法synchronized void method()对象锁
static synchronized void method()类锁

同一个对象锁/类锁,同一时刻只能被一个线程获取。对于小白玩家,这些就是大概了,再多的了解可以看《深入理解Java虚拟机》、《Java编程思想》等书,https://www.cnblogs.com/zaizhoumo/p/7700161.html 这篇博客也不错。

 

wait、notify、notifyAll

这三个一般都放在一块儿说,因为都是在synchronized的同步块中使用的。(思考一下为什么必须在同步块中使用?)

锁的管理是通过Monitor来完成的,Monitor维护着WaitSet和EntryList、owner。WaitSet里的线程必须被notify/notifyAll唤醒,才能进入EntryList,EntryList中的线程准备争夺锁并等待锁被释放,owner是当前获得锁的线程,owner的线程在wait()方法之后会进入WaitSet。所以这三个状态是互相转换的。

notify和notifyAll的区别从字面可以理解,notify是只唤醒一个WaitSet中的线程进入EntryList,notifyAll是唤醒全部WaitSet中的线程进入EntryList。假设WaitSet中有5个线程等待被唤醒,notify之后,WaitSet中还剩4个线程,被唤醒的线程参与锁的竞争;notifyAll之后,WaitSet中的线程全部被唤醒,参与锁的竞争。

接前面的问题,为什么这三个方法必须在同步块中使用?因为owner是当前获得对象锁的线程,如果没有获得锁,就没法继续后面的wait、notify、notifyAll,会报"java.lang.IllegalMonitorStateException:current thread not owner"异常。

小tips:永远在循环中调用wait()

wait之后的线程被谁唤醒是不可知的,假设一个场景:“多线程生产,多线程消费”。

synchronized(this) {
    if (empty) {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    remove();
    notifyAll();
}
synchronized(this) {
    while(empty) {//被唤醒后再次检查条件
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    remove();
    notifyAll();
}

这里有两段代码,一个是if判断,一个是while循环判断。消费者发现empty条件成立时会进入等待,因为生产者和消费者都是多个线程,如果唤醒这个消费者线程的是别的消费者线程,那么第一段代码就会走到remove()方法,可能会出现意料之外的异常。而第二段代码在线程被唤醒后还会再次判断,保证了remove()的前置条件。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值