【Java】MultiThread 多线程 Re02 线程通讯
一、等待与唤醒
/**
* 线程通讯问题
* Object wait, notify, notifyAll
* Condition await signal signAll
* CountDownLatch 当前线程等待若干个其他线程执行完成之后再执行
* CyclicBarrier 一组线程等待某个状态之后再全部开始执行
* Semaphore 控制某一组资源的访问权限
*/
- 代码案例,奇数线程打印奇数,偶数线程打印偶数
1、使用Object自带的方法实现等待与唤醒:
/**
* 休眠唤醒案例
* 打印10以内的奇偶数
* 奇数线程打印,偶数线程等待
*
* 这个案例使用锁对象实现
*/
static class OddAndEvenDemo {
private int printNo = 0;
private Object lockObj = new Object();
/**
* 奇数打印方法,由奇数线程调用
*/
public void odd() {
while (printNo < 10) {
synchronized (lockObj) {
if (!isEvenNo(printNo)) {
System.out.println("奇数:" + printNo);
printNo ++;
lockObj.notify();
} else {
try {
lockObj.wait(); // 等待偶数线程执行完毕
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
}
} /**
* 偶数打印方法,偶数线程调用
*/
public void even() {
while (printNo < 10) {
synchronized (lockObj) {
if (isEvenNo(printNo)) {
System.out.println("偶数:" + printNo);
printNo ++;
lockObj.notify();
} else {
try {
lockObj.wait(); // 等待偶数线程执行完毕
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
}
}
}
判断是否奇偶数的方法:
static boolean isEvenNo(int evenNo) {
return evenNo % 2 == 0;
}
执行部分:
/**
* 使用锁对象自身的等待与唤醒方法实现
*/
@Test
public void useLockObj() {
OddAndEvenDemo oddAndEvenDemo = new OddAndEvenDemo(); // 开启奇数线程
Thread oddThread = new Thread(() -> oddAndEvenDemo.odd());
// 开启偶数线程
Thread evenThread = new Thread(() -> oddAndEvenDemo.even());
oddThread.start();
evenThread.start();
}
2、使用Condition实现等待与唤醒:
/**
* 等待唤醒Condition方法
*/
static class OddAndEvenDemo2 {
private int printNo = 0;
private Lock lock = new ReentrantLock(); // 不设置为公平锁
private Condition condition = lock.newCondition();
/**
* 奇数打印方法,由奇数线程调用
*/
public void odd() {
while (printNo < 10) {
lock.lock();
try {
if (!isEvenNo(printNo)) {
System.out.println("奇数:" + printNo);
printNo ++;
condition.signal();
} else {
try {
condition.await();
} catch (Exception exception) {
exception.printStackTrace();
}
}
} catch (Exception exception) {
exception.printStackTrace();
} finally {
lock.unlock();
}
}
} /**
* 偶数打印方法,偶数线程调用
*/
public void even() {
while (printNo < 10) {
lock.lock();
try {
if (isEvenNo(printNo)) {
System.out.println("偶数:" + printNo);
printNo ++;
condition.signal();
} else {
try {
condition.await(); // 等待偶数线程执行完毕
} catch (Exception exception) {
exception.printStackTrace();
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
}
执行部分:
/**
* 使用Condition对象方法实现
*/
@Test
public void useCondition() {
OddAndEvenDemo2 oddAndEvenDemo = new OddAndEvenDemo2(); // 开启奇数线程
Thread oddThread = new Thread(() -> oddAndEvenDemo.odd());
// 开启偶数线程
Thread evenThread = new Thread(() -> oddAndEvenDemo.even());
oddThread.start();
evenThread.start();
}
- Object方法和Condition的区别总结:
1、Object锁对象基于同步关键字组合使用,等待与唤醒都是使用Object的wait & notify 且锁使用syncornized
2、Condition用于配合Lock对象组合使用,等待与唤醒使用 signal & await方法
二、指定数量等待 CountDownLatch
代码案例:
设置三个运动员线程和一个教练线程
只有等待三个运动员线程准备就绪之后,教练线程开始吹口哨开始训练
package cn.cloud9.test.multithread; import java.util.concurrent.CountDownLatch; /**
*
*/
public class CountDownLatchDemo { static class CoachRacerDemo {
private CountDownLatch cdl = new CountDownLatch(3); // 设置需要等待的线程数量 /**
* 运动员方法
*/
public void racer() {
// 获取线程名称
String name = Thread.currentThread().getName();
System.out.println(name + " is preparing ... ");
try {
Thread.sleep(1000); } catch (Exception exception) {
exception.printStackTrace();
}
System.out.println(name + " is ready!");
cdl.countDown();
} /**
* 教练方法
*/
public void coach() {
String name = Thread.currentThread().getName();
System.out.println(name + " wait racer prepare ready ...");
try {
cdl.await();
} catch (Exception exception) {
exception.printStackTrace();
}
System.out.println("all racer is ready! start training!");
} } public static void main(String[] args) {
CoachRacerDemo coachRacerDemo = new CoachRacerDemo();
Thread racer1 = new Thread(() -> coachRacerDemo.racer(), "racer-01");
Thread racer2 = new Thread(() -> coachRacerDemo.racer(), "racer-02");
Thread racer3 = new Thread(() -> coachRacerDemo.racer(), "racer-03"); Thread coach = new Thread(() -> coachRacerDemo.coach(), "coach"); // coach线程会先等待其他线程执行,直到等待数量的线程都执行完毕之后开始继续执行
coach.start();
racer1.start();
racer2.start();
racer3.start();
}
}
三、统一执行 CyclicBarrier
package cn.cloud9.test.multithread; import java.util.Date;
import java.util.concurrent.CyclicBarrier; /**
* CyclicBarrier
* 作用:
* 让一组线程等待到某个状态之后,再全部同时执行
* CyclicBarrier底层基于 ReentrantLock和Condition实现
*
*/
public class CyclicBarrierDemo { static class RunTogetherDemo {
final CyclicBarrier cyclicBarrier = new CyclicBarrier(3); // 参与同时起跑的线程数 public void startThread(int sec) {
String name = Thread.currentThread().getName();
System.out.println(name + " 正在准备...");
try {
Thread.sleep(sec);
cyclicBarrier.await();
} catch (Exception exception) {
exception.printStackTrace();
}
System.out.println(name + " 已经启动完毕:" + new Date().getTime());
}
} public static void main(String[] args) {
final RunTogetherDemo cyclicBarrierDemo = new RunTogetherDemo();
Thread thread1 = new Thread(() -> cyclicBarrierDemo.startThread(300));
Thread thread2 = new Thread(() -> cyclicBarrierDemo.startThread(400));
Thread thread3 = new Thread(() -> cyclicBarrierDemo.startThread(500));
thread1.start();
thread2.start();
thread3.start();
} }
执行之后三个线程会在同一时刻开始执行await方法后的代码块
尽管之前让线程睡眠了不同时长,最后启动完毕的时间戳是一样的
四、资源访问控制 Semaphore
代码案例:
8个工人 使用 3台机器,机器为互斥资源(即每次只能让一个工人来操作)
package cn.cloud9.test.multithread; import java.util.concurrent.Semaphore; /**
* 互斥案例
*/
public class SemaphoreDemo { /**
*
*/
static class WorkMachineDemo implements Runnable {
private int worker;
private Semaphore semaphore; public WorkMachineDemo(int worker, Semaphore semaphore) {
this.worker = worker;
this.semaphore = semaphore;
} @Override
public void run(){
try {
// 1、工人获取机器
semaphore.acquire();
// 2、打印工人获取到机器,开始工作
String name = Thread.currentThread().getName();
System.out.println(name + " 获取到机器,开始作业");
// 3、线程睡眠一秒,模拟工人机器操作中
Thread.sleep(1000);
// 3、使用完毕,工人下机
semaphore.release();
System.out.println(name + " 作业完毕,工人下机");
} catch (Exception exception) {
exception.printStackTrace();
}
}
} public static void main(String[] args) {
int worker = 8;
Semaphore semaphore = new Semaphore(3);
WorkMachineDemo workMachineDemo = new WorkMachineDemo(worker, semaphore);
for (int i = 0; i < worker; i++) {
new Thread(workMachineDemo).start();
}
}
}
【Java】MultiThread 多线程 Re02 线程通讯的更多相关文章
- Java:多线程,线程同步,同步锁(Lock)的使用(ReentrantLock、ReentrantReadWriteLock)
关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨Lock对象. synchronize ...
- 【java】-- 多线程之间实现通讯
1.多线程之间如何实现通讯 1.1.什么是多线程之间通讯? 多线程之间通讯,其实就是多个线程在操作同一个资源,但是操作的动作不同. 画图演示 1.2.多线程之间通讯需求 需求:第一个线程写入(inpu ...
- Java 基础 多线程和线程池基础
一,多线程 1.1 多线程介绍 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是进程中的一个执行单元,负 ...
- java 中多线程之间的通讯之生产者和消费者 (多个线程之间的通讯)
在真实开发 中关于多线程的通讯的问题用到下边的例子是比较多的 不同的地方时if 和while 的区别 如果只是两个线程之间的通讯,使用if是没有问题的. 但是在多个线程之间就会有问题 /* * 这个例 ...
- Java:多线程,线程池,使用CompletionService通过Future来处理Callable的返回结果
1. 背景 在Java5的多线程中,可以使用Callable接口来实现具有返回值的线程.使用线程池的submit方法提交Callable任务,利用submit方法返回的Future存根,调用此存根的g ...
- java核心技术-多线程之线程内存模型
对于每一种编程语言,理解它的内存模型是理所当然的重要.下面我们从jvm的内存模型来体会下java(不限java语言,严格来讲是JVM内存模型,所有JVM体系的变成语言均适用)的内存模型. 堆: 就是我 ...
- java核心-多线程(4)-线程类基础知识
1.并发 <1>使用并发的一个重要原因是提高执行效率.由于I/O等情况阻塞,单个任务并不能充分利用CPU时间.所以在单处理器的机器上也应该使用并发. <2>为了实现并发,操作系 ...
- java 中多线程之间的通讯之等待唤醒机制
wait notify () nitifyAll () 都使用在同步中,因为要对持有监视器(锁)的线程操作 所以要使用在同步中,因为只有同步才具有锁 为什么这些操作线程的方法要定义object类中呢 ...
- java核心技术-多线程之线程基础
说起线程,无法免俗首先要弄清楚的三个概念就是:进程.线程.协程.OK,那什么是进程,什么是线程,哪协程又是啥东西.进程:进程可以简单的理解为运行在操作系统中的程序,程序时静态代码,进程是动态运行着的代 ...
- Java:多线程,线程池,ThreadPoolExecutor详解
1. ThreadPoolExecutor的一个常用的构造方法 ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepA ...
随机推荐
- MySQL 导出一条数据的插入语句
1.MySQL 导出一条数据的插入语句的方法 在MySQL中,如果我们想要导出一条数据的插入语句,我们可以使用SELECT ... INTO OUTFILE语句(但这通常用于将整个表或查询结果导出到一 ...
- Nodejs概述 安装Nodejs os模块 path模块 url模块 querystring模块
一.Nodejs概述 介绍 相关网址: https://nodejs.org/zh-cn/ http://nodejs.cn/ Node.js 是一个开源与跨平台的JavaScript 运行时环境.它 ...
- P7448
problem & 双倍经验 & blog 低配版本 没有 Ynoi 标志性算法卡常,这点差评. 拆解问题 定义 \(lst_i\) 为上一个和 \(i\) 号点相同的位置. 由于几个 ...
- Spring AOP 中@Pointcut的用法(多个Pointcut)
Spring AOP 中@Pointcut的用法(多个Pointcut) /** swagger切面,分开来写 **/ @Aspect @Component public class ApiOpera ...
- .net core SM2加密+PKCS8实现
前阵子在对接银行接口,对方给出的加密方式是SM2,在网上找了不少教程,都是使用Portable.BouncyCastle实现的,功能实现后发现对方给出的密钥格式是PKCS8,下面代码记录一下PKCS8 ...
- 阿里云日志Nginx日志分析
每分钟接口访问次数的前200条统计 not request_uri : "/heartbeat.html" | SELECT time_series(time, '1m', '%H ...
- 【资料分享】Xilinx Zynq-7010/7020工业核心板规格书(双核ARM Cortex-A9 + FPGA,主频766MHz)
1 核心板简介 创龙科技SOM-TLZ7x是一款基于Xilinx Zynq-7000系列XC7Z010/XC7Z020高性能低功耗处理器设计的异构多核SoC工业核心板,处理器集成PS端双核ARM Co ...
- 【OpenVINO™】YOLOv10在CPU上也能实现50+FPS推理—使用OpenVINO C++部署YOLOv10
英特尔发行版 OpenVINO 工具套件基于 oneAPI 而开发,可以加快高性能计算机视觉和深度学习视觉应用开发速度工具套件,适用于从边缘到云的各种英特尔平台上,帮助用户更快地将更准确的真实世界 ...
- Windows服务器安全检查
为降低windows服务器系统的脆弱性,除了补丁及时更新,还建议加强系统账号的管理. 1.精简系统登录账号,最小化登录权限 检查方法:开始->运行->compmgmt.msc(计算机管理) ...
- Mybatis ResultMap复杂对象一对多查询结果映射之collection
Mybatis复杂对象一对多映射配置ResultMap的collection collection:一对多查询结果映射,比如user有多个订单 表结构 项目结构图 pom.xml <?xml v ...