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. nginx.conf配置项

    环境:centos7  nginx1.16.1 以下配置均在配置文件中进行:/etc/nginx/nginx.conf 1.设置工作进程的所有者和所属组 user  所有者  所属组: 设置后要在操作 ...

  2. Appium中wait_activity的使用以及XPATH定位

    # -*- coding:utf-8 -*- from appium import webdriver from time import sleep desired_caps ={ 'platform ...

  3. shell脚本攻略1

    换行符 \n echo -n 禁止换行 环境变量声明export export PATH="$PATH:/home/user/bin" 获取字符串的长度 length=${#var ...

  4. Css背景设置 、

    每天进步一小步,一年进步一大步. 第一次发博客园文章,主要记录自己学习的一个过程. CSS3 背景 CSS3 包含多个新的背景属性,它们提供了对背景更强大的控制. background-size ba ...

  5. oracle row_number() over(partition by .. order by ..)和rank() over(partition by .. order by ..) 和dense_rank() over(partition by .. order by ..)的相似点与区别

    新建一个测试表 create table dim_ia_test2(device_number varchar2(20),desc2 varchar2(20)) 插入数据后得到: 一.oracle r ...

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

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

  7. vector rIterator

    #include<vector> #include<iostream> using namespace std; void main() { vector<int> ...

  8. firstResponder

    https://developer.apple.com/library/content/documentation/EventHandling/Conceptual/EventHandlingiPho ...

  9. input type=file实现图片上传

    <label for="file"> <img src="images/morende.jpg" alt=""> & ...

  10. java之Matcher类详解

    在JDK 1.4中,Java增加了对正则表达式的支持. java与正则相关的工具主要在java.util.regex包中:此包中主要有两个类:Pattern.Matcher. Matcher  声明: ...