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多线程(五)线程通讯的更多相关文章

  1. Java多线程(五) —— 线程并发库之锁机制

    参考文献: http://www.blogjava.net/xylz/archive/2010/07/08/325587.html 一.Lock与ReentrantLock 前面的章节主要谈谈原子操作 ...

  2. Java多线程之线程的通信

    Java多线程之线程的通信 在总结多线程通信前先介绍一个概念:锁池.线程因为未拿到锁标记而发生的阻塞不同于前面五个基本状态中的阻塞,称为锁池.每个对象都有自己的锁池的空间,用于放置等待运行的线程.这些 ...

  3. Java多线程02(线程安全、线程同步、等待唤醒机制)

    Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...

  4. java多线程与线程间通信

    转自(http://blog.csdn.net/jerrying0203/article/details/45563947) 本文学习并总结java多线程与线程间通信的原理和方法,内容涉及java线程 ...

  5. Java多线程之线程协作

    Java多线程之线程协作 一.前言 上一节提到,如果有一个线程正在运行synchronized 方法,那么其他线程就无法再运行这个方法了.这就是简单的互斥处理. 假如我们现在想执行更加精确的控制,而不 ...

  6. Java多线程与线程池技术

    一.序言 Java多线程编程线程池被广泛使用,甚至成为了标配. 线程池本质是池化技术的应用,和连接池类似,创建连接与关闭连接属于耗时操作,创建线程与销毁线程也属于重操作,为了提高效率,先提前创建好一批 ...

  7. Java多线程之线程其他类

    Java多线程之线程其他类 实际编码中除了前面讲到的常用的类之外,还有几个其他类也有可能用得到,这里来统一整理一下: 1,Callable接口和Future接口 JDK1.5以后提供了上面这2个接口, ...

  8. Java多线程之线程的同步

    Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...

  9. Java多线程之线程的控制

    Java多线程之线程的控制 线程中的7 种非常重要的状态:  初始New.可运行Runnable.运行Running.阻塞Blocked.锁池lock_pool.等待队列wait_pool.结束Dea ...

  10. Java多线程父子线程关系 多线程中篇(六)

    有的时候对于Java多线程,我们会听到“父线程.子线程”的概念. 严格的说,Java中不存在实质上的父子关系 没有方法可以获取一个线程的父线程,也没有方法可以获取一个线程所有的子线程 子线程的消亡与父 ...

随机推荐

  1. CentOS6.7搭建部署DHCP服务 (详解主配置文件)

    DHCP服务 dhcp:动态主机配置协议.从bootp演变而来,引进了租约.续租功能,成为了现在的DHCP. 需要就分配,不需要就回收. 工作过程: 1.当获得地址是,有租约期限,当你关机时,IP地址 ...

  2. Socket网络编程-SocketServer

    Socket网络编程-SocketServer 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.SocketServer概述 socket编程过于底层,编程虽然有套路,但是想要写 ...

  3. JVM垃圾收集算法之清除算法

    最近看了一些大佬的博文,文中提到说:学习知识不能一味的死学滥学,在学之前要明白为什么要学这个知识,在实际的应用中怎么运用这个知识.我觉得说的很对,很多时候我学习确实是了解了这是什么原理,但是要说到实际 ...

  4. C++学习(12)—— 运算符重载

    运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型 1.加号运算符重载 作用:实现两个自定义数据类型相加的运算 #include <iostream> #i ...

  5. PHP中的生成器

    python中有的,php一样不落下呀. <?php //生成器 //生成器代理 //生成器返回表达示 function gen1() { yield '1'; yield '2'; yield ...

  6. Educational Codeforces Round 69 (Rated for Div. 2) E. Culture Code

    Educational Codeforces Round 69 (Rated for Div. 2) E. Culture Code 题目链接 题意: 给出\(n\)个俄罗斯套娃,每个套娃都有一个\( ...

  7. C#串口关闭SerialPort.Close()导致的卡死

    https://blog.csdn.net/fengda2870/article/details/51554838上面的链接给出了提示: 将Invoke变为BeginInvoke. 亲测可行. pri ...

  8. git 学习记录—— git 中的仓库、文件状态、修改和提交操作等

    最近开始学习使用版本控制工具  git .学习方式主要通过阅读 git 网站上的 Pro git 和动手实践,使用的系统为 Ubuntu16.04LTS,以及 Windows 8.1. 本文主要关注 ...

  9. python基础语法9 生成器,面向对象编程思想,三元表达式,列表生成式,生成器表达式(生成式),匿名函数,内置函数

    生成器 1.什么是生成器? 生成的工具. 生成器是一个 "自定义" 的迭代器, 本质上是一个迭代器. 2.如何实现生成器 但凡在函数内部定义了的yield, 调用函数时,函数体代码 ...

  10. websocket 浅学

    websocket ,可以实现客户端与服务器的即时通讯,比如即时聊天,获取项目中的消息提醒等(小铃铛上的标红数字提醒) 话不多说,上马奔腾,走起 只写demo,不在项目中使用: 1.初始化项目, np ...