educoder 使用线程锁(lock)实现线程同步_线程间的通信(一)
这篇文章主要从4个角度来讲多线程间的通信:
- 使用wait/notify实现线程间的通信
- 生产者/消费者模式的实现
- 方法join的使用
- ThreadLocal类的使用
等待/通知机制的实现:
(1)wait()方法属于Object类,作用是让当前执行代码的线程进行等待,该方法用来将当前线程置于"预执行队列"中,并且在wait()所在的代码行处停止执行,直到接到通知或者被中断为止。在调用wait()方法之前,线程必须获得该对象的对象级别锁,只能在同步方法或者同步块中调用wait()方法。在执行wait()方法后,当前线程释放锁。在从wait()返回前,线程与其他线程竞争重新获得锁。如果调用wait()时没有持有适当的锁,就会抛出IllegalMonitorStateException异常,它是RuntimeException的一个子类。因此不需要进行异常捕获。
此处有个面试题,是关于为什么wait()方法必须在同步中?占小狼的公众号给出了答案,lost wake up问题,作者给出了生产和消费的模式距离来说明lost wake up问题,并给出要解决就必须同步,获取同一对象锁,连接如下:
阿里面试题,为什么wait()方法要放在同步块中?mp.weixin.qq.com
(2)notify()方法也需要在同步方法或者同步代码块中调用,在调用前,线程必须获得该对象级别的锁,如果调用notify()时没有持有适当的锁,就会抛出IllegalMonitorStateException异常。该方法用来通知那些可能等待对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随机挑选其中一个呈wait状态的线程,对其发出notify,并使它等待获取该对象的对象锁。需要说明的是,在执行notify()方法后,当前线程不会马上释放锁,呈wait状态的线程也不会马上获得锁,必须等到notify()方法的线程执行完,走出同步代码块或则方法的时候,当前线程才会释放锁,wait状态的线程才可以获得锁。
notify()方法可以随机唤醒等待队列中等待同一共享资源的一个线程,并使线程退出等待队列,进入可运行的状态,该方法一次只可以唤醒一个线程。
notifyAll()方法是可以唤醒所有正在等待队列中等待同一共享资源的全部线程,让其从等待状态退出,进入可运行状态,谁的优先级高,谁将会先被执行,也有可能随机执行,取决于JVM虚拟机的实现。
下面这段代码,因为没有“对象监视器”,没有同步锁的原因,所以出现了异常
package
异常:
Exception
下面这段代码,虽然使用了synchronized关键字,而且wait方法也在同步块中,但是因为当前线程main被挂起,一直处于等待,所以wait()方法后面的代码都没有执行机会。
package
运行结果:
sync
下面这段代码实现了线程间的通信,线程A先启动执行,然后调用wait方法,线程睡眠3秒,然后线程B启动执行,并执行了notify()方法,通知唤醒wait()的线程,当线程B执行完synchronized同步代码块,然后释放了对象锁,wait()的线程获取到了对象锁,然后继续执行。
package
运行结果:
begin
下面这段代码,是当list中添加元素5个的时候,然后就notify()另外一个wait()的线程。
package
运行结果:
wait
从运行结果可以看出,最开始是wait begin,结束是wait end。
线程的生命周期:
大致分为创建、可运行、运行、阻塞、销毁等五个状态。
其中可运行状态和运行状态可以相互转换,阻塞状态和可运行状态可以相互转换。
线程进入Runnable状态的情况:
(1)调用sleep()方法后经过的时间超过了指定的休眠时间
(2)线程调用的阻塞IO已经返回,阻塞方法执行完毕
(3)线程成功得获得了试图同步的监视器
(4)线程正在等待某个通知,其他线程发出了通知
(5)处于挂起状态的线程调用了resume方法恢复线程
线程出现阻塞状态的情况:
(1)线程调用sleep方法,主动放弃占用的处理器资源
(2)线程调用了阻塞式IO方法,在方法返回前,该线程被阻塞
(3)线程试图获得一个同步监视器,但是该同步监视器正被其他线程所持有
(4)线程等待某个通知
(5)程序调用了suspend()方法,挂起该线程,此方法容易导致死锁,应该避免调用。
wait方法执行后,锁会自动释放;notify()方法执行后,锁不会自动释放,除非执行完对应的synchronized方法,才会释放锁;sleep方法也是不释放锁的(????sleep方法不是指定线程休眠时间,休眠时间过后,线程就i 重新获得CPU,去执行吗????我的理解:多线程情况下,其中一个线程在同步块中被指定休眠时间,这个线程是在休眠期间不会释放锁,在休眠结束,同步块执行完以后就会释放对象锁)。
执行完同步代码块会释放对象锁;
在执行同步代码块的过程中,如果遇到异常导致线程终止,锁也会被释放;
在执行同步代码块的过程中,执行了锁所属对象的wait()方法,这个线程会释放对象锁,而此线程对象会进入线程等待池中,等待被唤醒。
wait(long)方法:等待某一时间内是否有线程对锁进行唤醒,如果超过这个时间则自动唤醒。
下面代码使用wait,分别有两个线程执行,都执行了同步方法,从控制台可以看出,程序依然没有执行完,正是因为A线程执行了wait()方法后,释放了对象锁,B线程才可以获取对象锁,然后执行同步代码块,执行wait。
package
运行结果:
begin
下面的程序中使用了wait和notify结合,其中wait执行完,其他线程还可以继续执行同步代码块,但是执行到notify的时候,程序就一直不能结束,原因是notify()方法指定完后没有释放对象锁,所以才导致这个问题发生,代码和运行结果如下所示:
package
begin
当interrupt()方法和wait()方法相遇,下面是示例代码和运行结果:
package
begin
下面这段代码是关于notify()方法,一次只可以唤醒一个线程(随机)的验证:
package
程序运行结果:
begin
多线程中的生产者和消费者模式:
(1)一个生产者和一个消费者:操作值
package
运行结果:set和get交替执行
set
(2)多生产者与多消费者:操作值:假死
下面的这段代码,因为存在使用notify(),可能生产唤醒生产者,消费者唤醒消费者,所以会造成假死状态。
package
运行结果:
productor
educoder 使用线程锁(lock)实现线程同步_线程间的通信(一)相关推荐
- android 线程锁Lock
今天,简单讲讲android的线程锁 Lock的使用. 这个其实和SynchronizedClass 是一样的.我记得我的一篇博客写过这个内容.再次记录一下. 一.同步机制关键字synchron ...
- 孤荷凌寒自学python第三十九天python 的线程锁Lock
孤荷凌寒自学python第三十九天python的线程锁Lock (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 当多个线程同时操作一个文件等需要同时操作某一对象的情况发生时,很有可能发生冲突, ...
- educoder 使用线程锁(lock)实现线程同步_性能:Lock的锁之优化
Lock / synchronized Lock锁的基本操作是通过乐观锁实现的,由于Lock锁也会在阻塞时被挂起,依然属于悲观锁 synchronizedLock实现方式JVM层实现Java底层代码实 ...
- educoder 使用线程锁(lock)实现线程同步_Python并行编程(二):多线程锁机制利用Lock与RLock实现线程同步
什么是锁机制? 要回答这个问题,我们需要知道为什么需要使用锁机制.前面我们谈到一个进程内的多个线程的某些资源是共享的,这也是线程的一大优势,但是也随之带来一个问题,即当两个及两个以上的线程同时访问共享 ...
- java同步关键词解释、synchronized、线程锁(Lock)
1.java同步关键词解释 21.1 synchronized synchronized是用来实现线程同步的!!! 加同步格式: synchronized( 需要一个任意的对象(锁) ){ 代码块中放 ...
- 使用线程锁(lock)实现线程同步_一文搞懂Java多线程使用方式、实现原理以及常见面试题...
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
- Java多线程编程-(5)-使用Lock对象实现同步以及线程间通信
前几篇: Java多线程编程-(1)-线程安全和锁Synchronized概念 Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性 Java多线程编程-(3)-线程本地Th ...
- python 线程锁_Python3多线程执行任务含线程同步锁
Python启动多线程执行任务,用线程锁实现同步分配任务,最后等待所有线程执行完毕#python3多线程演示 import threading import random import time to ...
- C# 关于线程锁lock的使用方法
在多线程编程中,可能会有许多线程并发的执行一段代码(代码块A),以提高执行效率.在某些情况下,我们希望A中的代码块(B)同步的执行,即同一时刻只有一个线程执行代码块B,这就需要用到锁(lock).lo ...
最新文章
- 学习全基因组测序数据分析1:测序技术
- 黄金矿工游戏demo
- js php 中文乱码怎么解决_探讨PHP JSON中文乱码的解决方法详解
- unbuntu安装阿里云
- Python异常体系结构图
- Mysql数据库开发的36条原则
- python制作二维码
- php phpredis,PHP_PHP中redis的用法深入解析,redis是一个key-value存储系统。 - phpStudy...
- 设计模式系列之「装饰模式」
- 在linux中用高斯09优化分子结构,高斯09的优化 - 量子化学 - Gaussian - 小木虫论坛-学术科研互动平台...
- python 漏洞扫描器_自动扫描全网漏洞的扫描器
- 正式版苹果雪豹操作系统光盘镜像
- STM32L071 Flash写入的数据进行CRC-CCITT校验
- f开头的流媒体软件_流媒体直播工具(Streamon)
- 利用JavaScript实现一个简单的猜数字游戏
- 龙芯开源社区服务器迁移一览
- 阿里云远程桌面连接不到的问题
- 编译Linux驱动程序
- 如何计算两个坐标点的方位角
- fatfs文件系统详解之f_mkfs函数分析
热门文章
- ADS1220 使用FPGA调试
- frontpage编辑html,怎样用FrontPage软件编辑HTML帖子 | 音画代码学堂 - 中国音画家园 - Po...****...
- 小米10Pro手机双击android,小米10Pro:不完美,但很小米。
- php七牛分片上传_ThinkPHP实现JavaScript上传大视频到七牛云实例
- html font-family设置无效,css设置中文字体(font-family:黑体)后样式失效问题
- oracle 赋值到cmd,CMD操作oracle数据导库过程图解
- 小波相干wtc matlab,实现时间序列的小波相干性分析,并画出图谱
- python2.x和3.x的区别 print_Python2.x和Python3.x的区别
- linux python2.7 链接mysql导出数据库脚本_python备份文件以及mysql数据库的脚本代码...
- js 对象去除undefined_undefined和null区别