java多线程(五)线程通讯
1.1. 为什么要线程通信
多个线程并发执行时,在默认情况下CPU是随机切换线程的,有时我们希望CPU按我们的规律执行线程,此时就需要线程之间协调通信。
1.2. 线程通讯方式
线程间通信常用方式如下:
l 休眠唤醒方式:
Object的wait、notify、notifyAll
Condition的await、signal、signalAll
l CountDownLatch:用于某个线程A等待若干个其他线程执行完之后,它才执行
l CyclicBarrier:一组线程等待至某个状态之后再全部同时执行
l Semaphore:用于控制对某组资源的访问权限
1.2.1. 休眠唤醒方式
Object的wait、notify、notifyAll
package com.signal; /**
* @Auther: lanhaifeng
* @Date: 2019/11/21 0021 09:32
* @Description:使用Object类的通信
* @statement:
*/
public class WaitNotifyRunnable { private Object obj = new Object();
private Integer i=; //单数
public void odd() {
while(i<){
synchronized (obj){
if(i% == ){
System.out.println(Thread.currentThread().getName()+"【奇数】:"+i);
i++;
obj.notify();
} else {
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
} //双数
public void even(){
while(i<){
synchronized (obj){
if(i% == ){
System.out.println(Thread.currentThread().getName()+"【偶数】:"+i);
i++;
obj.notify();
} else {
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
} //测试
public static void main(String[] args){
final WaitNotifyRunnable runnable = new WaitNotifyRunnable();
Thread t1 = new Thread(new Runnable() {
public void run() {
runnable.odd();
}
}, "奇数线程");
Thread t2 = new Thread(new Runnable() {
public void run() {
runnable.even();
}
}, "偶数线程"); t1.start();
t2.start();
} }
运行效果:
Condition的await、signal、signalAll
package com.signal; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* @Auther: lanhaifeng
* @Date: 2019/11/21 0021 09:39
* @Description:使用Condition的await、signal
* @statement:
*/
public class AwaitSignalRunnable { private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private Integer i=; public void odd() {
while(i<){
lock.lock();
try{
if(i% == ){
System.out.println(Thread.currentThread().getName()+"【奇数】:"+i);
i++;
condition.signal();
} else {
condition.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
} }
} public void even(){
while(i<){
lock.lock();
try{
if(i% == ){
System.out.println(Thread.currentThread().getName()+"【偶数】:"+i);
i++;
condition.signal();
} else {
condition.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
} }
} //测试
public static void main(String[] args){
final WaitNotifyRunnable runnable = new WaitNotifyRunnable();
Thread t1 = new Thread(new Runnable() {
public void run() {
runnable.odd();
}
}, "奇数线程");
Thread t2 = new Thread(new Runnable() {
public void run() {
runnable.even();
}
}, "偶数线程"); t1.start();
t2.start();
} }
运行效果:
Object和Condition休眠唤醒区别
l object wait()必须在synchronized(同步锁)下使用,
l object wait()必须要通过Nodify()方法进行唤醒
l condition await() 必须和Lock(互斥锁/共享锁)配合使用
l condition await() 必须通过 signal() 方法进行唤醒
1.2.2. CountDownLatch方式
CountDownLatch是在java1.5被引入的,存在于java.util.concurrent包下。
CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。
每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
示例代码:
package com.signal; import java.util.concurrent.CountDownLatch; /**
* @Auther: lanhaifeng
* @Date: 2019/11/21 0021 09:46
* @Description:使用CountDownLatch
* 每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
* @statement:
*/
public class CountDown { private Integer i = ;
private CountDownLatch countDownLatch = new CountDownLatch();
//奇数
public void odd(){
while(i <){
if(i% == ){
System.out.println(Thread.currentThread().getName()+"【奇数】:"+i);
i++;
countDownLatch.countDown();
} else {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//偶数
public void even(){
while(i <){
if(i% == ){
System.out.println(Thread.currentThread().getName()+"【偶数】:"+i);
i++;
countDownLatch.countDown();
} else {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} //测试
public static void main(String[] args){
final CountDown countDown = new CountDown();
Thread t1 = new Thread(new Runnable() {
public void run() {
countDown.odd();
}
},"奇数");
Thread t2 = new Thread(new Runnable() {
public void run() {
countDown.even();
}
},"偶数");
t1.start();
t2.start();
} }
执行效果:
1.2.3. CyclicBarrier方式
CyclicBarrier是在java1.5被引入的,存在于java.util.concurrent包下。
CyclicBarrier实现让一组线程等待至某个状态之后再全部同时执行。
CyclicBarrier底层是
三个线程同时启动,示例代码如下:
package com.signal; import java.util.Date;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; /**
* @Auther: lanhaifeng
* @Date: 2019/11/21 0021 09:52
* @Description:使用CyclicBarrier
* CyclicBarrier实现让一组线程等待至某个状态之后再全部同时执行。
* @statement:
*/
public class CyclicBarrierDemo {
public static void main(String[] args){ final CyclicBarrier cyclicBarrier = new CyclicBarrier(); new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+":准备...");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"启动完毕:"+new Date().getTime());
}
},"线程1").start();
new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+":准备...");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"启动完毕:"+new Date().getTime());
}
},"线程2").start();
new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+":准备...");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"启动完毕:"+new Date().getTime());
}
},"线程3").start();
} }
执行效果如下:三个线程同时启动
1.2.4. Semaphore方式
Semaphore是在java1.5被引入的,存在于java.util.concurrent包下。
Semaphore用于控制对某组资源的访问权限。
工人使用机器工作,示例代码如下:
package com.signal; import java.util.concurrent.Semaphore; /**
* @Auther: lanhaifeng
* @Date: 2019/11/21 0021 09:56
* @Description: 使用Semaphore
* emaphore用于控制对某组资源的访问权限
* @statement:
*/
public class SemaphoreDemo {
static class Machine implements Runnable{ private int num;//工号
private Semaphore semaphore; public Machine(int num, Semaphore semaphore) {
this.num = num;
this.semaphore = semaphore;
} public void run() {
try {
semaphore.acquire();//请求机器
System.out.println("工人"+this.num+"请求机器,正在使用机器");
Thread.sleep();
System.out.println("工人"+this.num+"使用完毕,已经释放机器");
semaphore.release();//释放机器
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args){
int worker = ;//工人数
Semaphore semaphore = new Semaphore();//机器数
for (int i=; i< worker; i++){
new Thread(new Machine(i, semaphore)).start();
}
} }
执行效果如下:
1.3. 小结
1.3.1. sleep和wait区别
1.3.2. wait和notify区别
wait和notify都是Object中的方法
wait和notify执行前线程都必须获得对象锁
wait的作用是使当前线程进行等待
notify的作用是通知其他等待当前线程的对象锁的线程
java多线程(五)线程通讯的更多相关文章
- Java多线程(五) —— 线程并发库之锁机制
参考文献: http://www.blogjava.net/xylz/archive/2010/07/08/325587.html 一.Lock与ReentrantLock 前面的章节主要谈谈原子操作 ...
- Java多线程之线程的通信
Java多线程之线程的通信 在总结多线程通信前先介绍一个概念:锁池.线程因为未拿到锁标记而发生的阻塞不同于前面五个基本状态中的阻塞,称为锁池.每个对象都有自己的锁池的空间,用于放置等待运行的线程.这些 ...
- Java多线程02(线程安全、线程同步、等待唤醒机制)
Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...
- java多线程与线程间通信
转自(http://blog.csdn.net/jerrying0203/article/details/45563947) 本文学习并总结java多线程与线程间通信的原理和方法,内容涉及java线程 ...
- Java多线程之线程协作
Java多线程之线程协作 一.前言 上一节提到,如果有一个线程正在运行synchronized 方法,那么其他线程就无法再运行这个方法了.这就是简单的互斥处理. 假如我们现在想执行更加精确的控制,而不 ...
- Java多线程与线程池技术
一.序言 Java多线程编程线程池被广泛使用,甚至成为了标配. 线程池本质是池化技术的应用,和连接池类似,创建连接与关闭连接属于耗时操作,创建线程与销毁线程也属于重操作,为了提高效率,先提前创建好一批 ...
- Java多线程之线程其他类
Java多线程之线程其他类 实际编码中除了前面讲到的常用的类之外,还有几个其他类也有可能用得到,这里来统一整理一下: 1,Callable接口和Future接口 JDK1.5以后提供了上面这2个接口, ...
- Java多线程之线程的同步
Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...
- Java多线程之线程的控制
Java多线程之线程的控制 线程中的7 种非常重要的状态: 初始New.可运行Runnable.运行Running.阻塞Blocked.锁池lock_pool.等待队列wait_pool.结束Dea ...
- Java多线程父子线程关系 多线程中篇(六)
有的时候对于Java多线程,我们会听到“父线程.子线程”的概念. 严格的说,Java中不存在实质上的父子关系 没有方法可以获取一个线程的父线程,也没有方法可以获取一个线程所有的子线程 子线程的消亡与父 ...
随机推荐
- 性能测试基础---LR关联
·什么时候需要做关联?一般来说,在脚本运行出错的时候,我们就可能需要进行关联处理. ·脚本出错分为两种情况: ·直接回放出错(失败).通常来说,如果录制成功,回放失败,排除数据的唯一性约束之后,那就必 ...
- C#中的事件的订阅与发布
认识发布者/订阅者模式 发布者定义一系列事件,并提供一个注册方法: 订阅者向发布者注册自己的事件处理逻辑,供一个可被回调的方法,也就是事件处理程序:当发布者的事件被触发的时候,订阅者将通过回调函数得到 ...
- Java并发(八)计算线程池最佳线程数
目录 一.理论分析 二.实际应用 为了加快程序处理速度,我们会将问题分解成若干个并发执行的任务.并且创建线程池,将任务委派给线程池中的线程,以便使它们可以并发地执行.在高并发的情况下采用线程池,可以有 ...
- CSS float 父元素高度自适应
<html> <head><title></title><style type="text/css">*{margin: ...
- linux下使用openssl生成https的crt和key证书
x509证书一般会用到三类文,key,csr,crt Key 是私用密钥openssl格,通常是rsa算法. Csr 是证书请求文件,用于申请证书.在制作csr文件的时,必须使用自己的私钥来签署申,还 ...
- Java Excel 导入导出(一)
本文主要描述通过java实现Excel导入导出 一.读写Excel三种常用方式 1.JXL——Java Excel开放源码项目:读取,创建,更新 2.POI——Apache POI ,提供API给Ja ...
- react native 开发问题分类
链接.编译.部署.运行: 一.语法问题:编译问题 二.链接问题: yarn add react-navigation react-native link react-navigation 三.部署问题 ...
- 协程 和 async await
协程, 是 为了 避免 闭包传递变量 的 性能损耗 而产生 . 如果不是 为了 避免 闭包传递变量 的 性能损耗 , 线程池 和 Task 已经够了, 不需要 再设计 出 协程 来 . 闭 ...
- 洛谷P3258 [JLOI]2014松鼠的新家
题目 树上差分 树上点差分,注意会出现路径端点多记录的情况,这时需要在最后输出的时候输出子树的差分数组的和-1,而不是在处理原数据的时候减1.并且a[n]不需要糖果,最后也减去就行. #include ...
- linux中的目录
Linux文件系统数如下: 在 Linux 系统中,文件系统通过目录"包含"子目录及文件的方式,来组织成一个树状结构.那么目录到底是如何"包含"其他目录及文件的 ...