一、等待与唤醒

/**
* 线程通讯问题
* 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. 算法学习笔记(13): Manacher算法

    Manacher算法 形象的被译为马拉车算法 这个算法用于处理简单的回文字符串的问题.可以在 \(O(n)\) 的复杂度内处理出每一个位置为中心的回文串的最长长度. 为了避免出现偶数长度的回文串,导致 ...

  2. LeetCode 72. Edit Distance 编辑距离 (C++/Java)

    题目: Given two words word1 and word2, find the minimum number of operations required to convert word1 ...

  3. 如何发现及处理 MySQL 主从延迟问题

    在 Percona MySQL 支持团队中,我们经常看到客户抱怨复制延迟的问题.当然,这对 MySQL 用户来说并不是什么新鲜事,多年来我们在 MySQL 性能博客上发表过一些关于这个主题的文章(过去 ...

  4. Winform绘制圆形图

    1 private void Form_Load(object sender, EventArgs e) 2 { 3 PictureBox pic = new PictureBox(); 4 pic. ...

  5. 题目:SHMIP The subglacial hydrology model intercomparison Project

    SHMIP(冰下水文模型比较计划)是一个致力于解决冰下水文多种理论方法问题的项目.该计划通过构建一系列综合模拟实验,并对运行这些模拟的各参与模型的结果进行比较,以达到其目标.这将有助于潜在的模型用户更 ...

  6. Vue学习:22.Vue组件库-Vant

    Vue组件库是一系列预先构建好的.可复用的UI组件集合,它们设计用于加速Vue.js应用程序的开发过程.这些组件通常遵循一定的设计规范,提供统一的外观和交互体验,让开发者能够快速搭建用户界面. 组件库 ...

  7. 比较 SpringSecurity 和 Shiro

    相比 Spring Security, Shiro 在保持强大功能的同时,使用简单性和灵活性. SpringSecurity: 即使是一个一个简单的请求, 最少得经过它的 8 个Filter.Spri ...

  8. Windows10(or windows11) Hyper-V 创建虚拟交换机后宿主机上传速度变特别慢的问题解决

    问题 我在我的win11上启用了Hyper-v,装了个虚拟机跑了个CentOS7.6,为了让centos和宿主机通信在同个网段搞了个桥接网络,网络环境如下 然后我测试一个文件上传功能的时候发现网络上传 ...

  9. echarts 各种特效图

    饼图标签展示数值 配置项: option = { title: { text: '项目时间分布', left: 'center' }, tooltip: { trigger: 'item', form ...

  10. 为什么不推荐使用Linq?

    相信很多.NETer看了标题,都会忍不住好奇,点进来看看,并且顺便准备要喷作者! 这里,首先要申明一下,作者本人也非常喜欢Linq,也在各个项目中常用Linq. 我爱Linq,Linq优雅万岁!!!( ...