一、等待与唤醒

/**
* 线程通讯问题
* 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 线程通讯的更多相关文章

  1. Java:多线程,线程同步,同步锁(Lock)的使用(ReentrantLock、ReentrantReadWriteLock)

    关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨Lock对象. synchronize ...

  2. 【java】-- 多线程之间实现通讯

    1.多线程之间如何实现通讯 1.1.什么是多线程之间通讯? 多线程之间通讯,其实就是多个线程在操作同一个资源,但是操作的动作不同. 画图演示 1.2.多线程之间通讯需求 需求:第一个线程写入(inpu ...

  3. Java 基础 多线程和线程池基础

    一,多线程 1.1 多线程介绍 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是进程中的一个执行单元,负 ...

  4. java 中多线程之间的通讯之生产者和消费者 (多个线程之间的通讯)

    在真实开发 中关于多线程的通讯的问题用到下边的例子是比较多的 不同的地方时if 和while 的区别 如果只是两个线程之间的通讯,使用if是没有问题的. 但是在多个线程之间就会有问题 /* * 这个例 ...

  5. Java:多线程,线程池,使用CompletionService通过Future来处理Callable的返回结果

    1. 背景 在Java5的多线程中,可以使用Callable接口来实现具有返回值的线程.使用线程池的submit方法提交Callable任务,利用submit方法返回的Future存根,调用此存根的g ...

  6. java核心技术-多线程之线程内存模型

    对于每一种编程语言,理解它的内存模型是理所当然的重要.下面我们从jvm的内存模型来体会下java(不限java语言,严格来讲是JVM内存模型,所有JVM体系的变成语言均适用)的内存模型. 堆: 就是我 ...

  7. java核心-多线程(4)-线程类基础知识

    1.并发 <1>使用并发的一个重要原因是提高执行效率.由于I/O等情况阻塞,单个任务并不能充分利用CPU时间.所以在单处理器的机器上也应该使用并发. <2>为了实现并发,操作系 ...

  8. java 中多线程之间的通讯之等待唤醒机制

    wait notify () nitifyAll () 都使用在同步中,因为要对持有监视器(锁)的线程操作 所以要使用在同步中,因为只有同步才具有锁 为什么这些操作线程的方法要定义object类中呢 ...

  9. java核心技术-多线程之线程基础

    说起线程,无法免俗首先要弄清楚的三个概念就是:进程.线程.协程.OK,那什么是进程,什么是线程,哪协程又是啥东西.进程:进程可以简单的理解为运行在操作系统中的程序,程序时静态代码,进程是动态运行着的代 ...

  10. Java:多线程,线程池,ThreadPoolExecutor详解

    1. ThreadPoolExecutor的一个常用的构造方法 ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepA ...

随机推荐

  1. MySQL 导出一条数据的插入语句

    1.MySQL 导出一条数据的插入语句的方法 在MySQL中,如果我们想要导出一条数据的插入语句,我们可以使用SELECT ... INTO OUTFILE语句(但这通常用于将整个表或查询结果导出到一 ...

  2. Nodejs概述 安装Nodejs os模块 path模块 url模块 querystring模块

    一.Nodejs概述 介绍 相关网址: https://nodejs.org/zh-cn/ http://nodejs.cn/ Node.js 是一个开源与跨平台的JavaScript 运行时环境.它 ...

  3. P7448

    problem & 双倍经验 & blog 低配版本 没有 Ynoi 标志性算法卡常,这点差评. 拆解问题 定义 \(lst_i\) 为上一个和 \(i\) 号点相同的位置. 由于几个 ...

  4. Spring AOP 中@Pointcut的用法(多个Pointcut)

    Spring AOP 中@Pointcut的用法(多个Pointcut) /** swagger切面,分开来写 **/ @Aspect @Component public class ApiOpera ...

  5. .net core SM2加密+PKCS8实现

    前阵子在对接银行接口,对方给出的加密方式是SM2,在网上找了不少教程,都是使用Portable.BouncyCastle实现的,功能实现后发现对方给出的密钥格式是PKCS8,下面代码记录一下PKCS8 ...

  6. 阿里云日志Nginx日志分析

    每分钟接口访问次数的前200条统计 not request_uri : "/heartbeat.html" | SELECT time_series(time, '1m', '%H ...

  7. 【资料分享】Xilinx Zynq-7010/7020工业核心板规格书(双核ARM Cortex-A9 + FPGA,主频766MHz)

    1 核心板简介 创龙科技SOM-TLZ7x是一款基于Xilinx Zynq-7000系列XC7Z010/XC7Z020高性能低功耗处理器设计的异构多核SoC工业核心板,处理器集成PS端双核ARM Co ...

  8. 【OpenVINO™】YOLOv10在CPU上也能实现50+FPS推理—使用OpenVINO C++部署YOLOv10

    ​ 英特尔发行版 OpenVINO 工具套件基于 oneAPI 而开发,可以加快高性能计算机视觉和深度学习视觉应用开发速度工具套件,适用于从边缘到云的各种英特尔平台上,帮助用户更快地将更准确的真实世界 ...

  9. Windows服务器安全检查

    为降低windows服务器系统的脆弱性,除了补丁及时更新,还建议加强系统账号的管理. 1.精简系统登录账号,最小化登录权限 检查方法:开始->运行->compmgmt.msc(计算机管理) ...

  10. Mybatis ResultMap复杂对象一对多查询结果映射之collection

    Mybatis复杂对象一对多映射配置ResultMap的collection collection:一对多查询结果映射,比如user有多个订单 表结构 项目结构图 pom.xml <?xml v ...