JUC(二)线程间通信
线程间通信
多线程编程步骤
- 创建资源类,编写属性和操作方法
- 在资源中的操作方法
- 判断
- 干活
- 通知
- 创建多个线程,调用资源类的操作方法
- 使用while循环进行条件判断,防止虚假唤醒问题
一个加减实例 & 虚假唤醒问题
实现对一个初始值0进行轮流加减操作
public class AddAndSub {
private int num;
public int getNum() {
return num;
}
public AddAndSub() {
num = 0;
}
public synchronized void add() {
// 判断
while(num != 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 业务逻辑
num++;
System.out.println(Thread.currentThread().getName() + " + 1");
// 通知
notifyAll();
}
public synchronized void sub() {
while(num != 1) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num--;
System.out.println(Thread.currentThread().getName() + " - 1");
notifyAll();
}
}
class RunAddAndSub {
public static void main(String[] args) {
AddAndSub addAndSub = new AddAndSub();
Runnable r1 = () -> {
for(int i = 0; i < 10; i++) {
addAndSub.add();
}
};
Runnable r2 = () -> {
for(int i = 0; i < 10; i++) {
addAndSub.sub();
}
};
new Thread(r1, "A").start();
new Thread(r2, "B").start();
System.out.println(addAndSub.getNum());
}
}
为什么要在条件判断使用while?
这是因为比如add方法A线程+1notifyAll后,可能是处于等待状态的C线程抢到了锁,但是这时候num并不是0,所以要使用while在线程唤醒后再次判断。这种问题称为虚假唤醒问题,
Lock接口实现
lock.newCondition设置等待条件
class Share {
private int num = 0;
private final Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void incr() {
lock.lock();
while(num != 0) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num++;
System.out.println(Thread.currentThread().getName() + " + 1");
condition.signalAll();
lock.unlock();
}
public void decr() {
lock.lock();
while(num == 0) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num--;
System.out.println(Thread.currentThread().getName() + " - 1");
condition.signalAll();
lock.unlock();
}
}
public class TheadDemo {
public static void main(String[] args) {
var share = new Share();
Runnable r1 = () -> {
for(int i = 0; i < 10; i++) {
share.incr();
}
};
Runnable r2 = () -> {
for(int i = 0; i < 10; i++) {
share.decr();
}
};;
new Thread(r1, "A").start();
new Thread(r2, "B").start();
new Thread(r1, "C").start();
new Thread(r2, "D").start();
}
}
注意condition.signalAll()要写在unlock之前
线程间定制化通信
如上面的四个线程执行的时候,只是+-线程的顺序执行,执行相同方法的线程是没有顺序的,规定相同方法的线程的执行顺序,即是线程的定制化通信。
线程间通信案例
启动三个线程,要求如下:
- AA打印5次,BB打印10次,CC打印15次
- 如此进行10轮
设置标志位
当标志位为1,AA执行,当标志位为2,BB执行,当标志位为3,CC执行
class Print {
private int flag = 1;
public synchronized void print5(int num) throws InterruptedException {
while (flag != 1) {
this.wait();
}
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ":::" + i + " ,loop" + num);
}
flag = 2;
this.notifyAll();
}
public synchronized void print10(int num) throws InterruptedException {
while (flag != 2) {
this.wait();
}
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":::" + i + " ,loop" + num);
}
flag = 3;
this.notifyAll();
}
public synchronized void print15(int num) throws InterruptedException {
while (flag != 3) {
this.wait();
}
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName() + ":::" + i + " ,loop" + num);
}
flag = 1;
this.notifyAll();
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
Print print = new Print();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
print.print5(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "AA").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
print.print10(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "BB").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
print.print15(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "CC").start();
}
}
JUC(二)线程间通信的更多相关文章
- juc包:使用 juc 包下的显式 Lock 实现线程间通信
一.前置知识 线程间通信三要素: 多线程+判断+操作+通知+资源类. 上面的五个要素,其他三个要素就是普通的多线程程序问题,那么通信就需要线程间的互相通知,往往伴随着何时通信的判断逻辑. 在 java ...
- Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)
一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会 ...
- JUC之线程间的通信
线程通信 视频1: 2021.12.18 JUC视频学习片段 对上次多线程编程步骤补充(中部): 创建资源类,在资源类中创建属性和操作方法 在资源类里面操作 判断 干活 通知 创建多个线程,调用资源类 ...
- Java多线程编程核心技术---线程间通信(二)
通过管道进行线程间通信:字节流 Java提供了各种各样的输入/输出流Stream可以很方便地对数据进行操作,其中管道流(pipeStream)是一种特殊的流,用于在不同线程间直接传送数据,一个线程发送 ...
- Java笔记(二十)……线程间通信
概述 当需要多线程配合完成一项任务时,往往需要用到线程间通信,以确保任务的稳步快速运行 相关语句 wait():挂起线程,释放锁,相当于自动放弃了执行权限 notify():唤醒wait等待队列里的第 ...
- 【原】iOS多线程之线程间通信和线程互斥
线程间通信 1> 线程间通信分为两种 主线程进入子线程(前面的方法都可以) 子线程回到主线程 2> 返回主线程 3> 代码 这个案例的思路是:当我触摸屏幕时,会在子线程加载图片,然后 ...
- Java线程间通信-回调的实现方式
Java线程间通信-回调的实现方式 Java线程间通信是非常复杂的问题的.线程间通信问题本质上是如何将与线程相关的变量或者对象传递给别的线程,从而实现交互. 比如举一个简单例子,有一个多线程的 ...
- 线程间通信的三种方式(NSThread,GCD,NSOperation)
一.NSThread线程间通信 #import "ViewController.h" @interface ViewController ()<UIScrollViewDel ...
- Windows环境下多线程编程原理与应用读书笔记(4)————线程间通信概述
<一>线程间通信方法 全局变量方式:进程中的线程共享全局变量,可以通过全局变量进行线程间通信. 参数传递法:主线程创建子线程并让子线程为其服务,因此主线程和其他线程可以通过参数传递进行通信 ...
- java线程间通信:一个小Demo完全搞懂
版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.从一个小Demo说起 上篇我们聊到了Java多线程的同步 ...
随机推荐
- Two Sum:给出一个整数数组,返回两个数的下标值,令其和等于一个指定的目标值 #Leetcode
// Given nums = [2, 7, 11, 15], target = 9, // Because nums[0] + nums[1] = 2 + 7 = 9, // return [0, ...
- airtest的手势滑动方法封装
这个网上应该很多类似的方法封装,各种实现方式也很多,但是感觉最简单实用的还是swipe了:代码很简单,直接上方法了. 很多方法都不会告诉你会导入什么包,其实很多小白入门可能就是这么简单的一步就被卡 ...
- Docker 安装 MySQL5.7
1.拉取数据库镜像 docker pull mysql:5.7 docker images命令查看镜像是否下载成功 docker images 2.配置mysql 创建mysql目录,用于存放mysq ...
- SQL Server链接数据库
有时候我们希望在一个sqlserver下访问另一个sqlserver数据库上的数据,或者访问其他oracle数据库上的数据,要想完成这些操作,我们首要的是创建数据库链接. 数据库链接能够让本地的一个s ...
- 面试-JVM
1.java内存模型 / java运行时数据区模型? 元空间属于本地内存 而非JVM内存 内存模型 程序计数器 1.作为字节码的行号指示器,字节码解释器通过程序计数器来确定下一步要执行的字节码指令,比 ...
- Java学习笔记-BigDecimal类型
1.介绍 Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更 ...
- TCP连接实践解析
1.初始化. 2.FD_ISSET,是select机制的一个成员,用来检测sockfd是否有动作,对应读写异常等. 3.FD_ZERO 宏完成的工作就是一个初始化套接字集合 4.FD_SET把sock ...
- [复现]2021 DASCTF X BUUOJ 五月大联动-PWN
[复现]2021 DASCTF X BUUOJ 五月大联动 由于我没ubuntu16就不复现第一个题了,直接第二个 正常的off by one from pwn import * context.os ...
- TensorFlow安装填坑之路(Windows环境)
最近跟着简单粗暴 TensorFlow 2中的教学活动ML Study Jam 2020学习TensorFlow,记录下在Windows环境中安装TensorFlow时遇到的那些坑. TensorFl ...
- pytorch之科学计算
一.简介 torch作为深度学习的主流框架,其根本在于1.具有强大的GPU加速的张量计算功能.2.包含自动求导系统的深度神经网络.自动求导功能由torch.Autograd模块实现,而科学计算部分则直 ...