线程间通信

多线程编程步骤

  1. 创建资源类,编写属性和操作方法
  2. 在资源中的操作方法
    1. 判断
    2. 干活
    3. 通知
  3. 创建多个线程,调用资源类的操作方法
  4. 使用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(二)线程间通信的更多相关文章

  1. juc包:使用 juc 包下的显式 Lock 实现线程间通信

    一.前置知识 线程间通信三要素: 多线程+判断+操作+通知+资源类. 上面的五个要素,其他三个要素就是普通的多线程程序问题,那么通信就需要线程间的互相通知,往往伴随着何时通信的判断逻辑. 在 java ...

  2. Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)

    一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会 ...

  3. JUC之线程间的通信

    线程通信 视频1: 2021.12.18 JUC视频学习片段 对上次多线程编程步骤补充(中部): 创建资源类,在资源类中创建属性和操作方法 在资源类里面操作 判断 干活 通知 创建多个线程,调用资源类 ...

  4. Java多线程编程核心技术---线程间通信(二)

    通过管道进行线程间通信:字节流 Java提供了各种各样的输入/输出流Stream可以很方便地对数据进行操作,其中管道流(pipeStream)是一种特殊的流,用于在不同线程间直接传送数据,一个线程发送 ...

  5. Java笔记(二十)……线程间通信

    概述 当需要多线程配合完成一项任务时,往往需要用到线程间通信,以确保任务的稳步快速运行 相关语句 wait():挂起线程,释放锁,相当于自动放弃了执行权限 notify():唤醒wait等待队列里的第 ...

  6. 【原】iOS多线程之线程间通信和线程互斥

    线程间通信 1> 线程间通信分为两种 主线程进入子线程(前面的方法都可以) 子线程回到主线程 2> 返回主线程 3> 代码 这个案例的思路是:当我触摸屏幕时,会在子线程加载图片,然后 ...

  7. Java线程间通信-回调的实现方式

    Java线程间通信-回调的实现方式   Java线程间通信是非常复杂的问题的.线程间通信问题本质上是如何将与线程相关的变量或者对象传递给别的线程,从而实现交互.   比如举一个简单例子,有一个多线程的 ...

  8. 线程间通信的三种方式(NSThread,GCD,NSOperation)

    一.NSThread线程间通信 #import "ViewController.h" @interface ViewController ()<UIScrollViewDel ...

  9. Windows环境下多线程编程原理与应用读书笔记(4)————线程间通信概述

    <一>线程间通信方法 全局变量方式:进程中的线程共享全局变量,可以通过全局变量进行线程间通信. 参数传递法:主线程创建子线程并让子线程为其服务,因此主线程和其他线程可以通过参数传递进行通信 ...

  10. java线程间通信:一个小Demo完全搞懂

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.从一个小Demo说起 上篇我们聊到了Java多线程的同步 ...

随机推荐

  1. can't convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.

    predict=predict.data.numpy() 这一行报错意思是:如果想把CUDA tensor格式的数据改成numpy时,需要先将其转换成cpu float-tensor随后再转到nump ...

  2. OSIDP-I/O管理和磁盘调度-11

    I/O设备 I/O设备分类:人可读.机器可读和远程通信三类. I/O设备之间的差别: 1.数据传送速率 2.应用领域 3.控制的复杂性 4.传送单位 5.数据表示形式 6.错误条件 I/O功能的组织 ...

  3. hdu: Dire Wolf(区间DP)

    Problem DescriptionDire wolves, also known as Dark wolves, are extraordinarily large and powerful wo ...

  4. Windows 解决teamview远程必须mstsc连接

    真实原因是你的TeamViewer一直在用远程桌面的ID进行登录,所以一旦远程桌面断开,TeamViewer就无法连接了.因此我们只需要切换为服务器的TeamViewer ID即可,服务器的TeamV ...

  5. Crypto入门 (七) Railfence (栏栅密码,正常型和W型)

    前言: Crypto中分三类,分别是编码.古典密码.现代密码,栏栅密码属于古典密码中得特殊移位密码,密钥只有 一个k,表示栏栅得长度.所谓栏栅密码就是将要加密得明文分成k个一组,然后取每组得第一个字符 ...

  6. 北京金橙子ezcad2和lmc1控制卡二次开发的动态连接库手册

    我要吐槽一下金橙子打电话过去一问三不答.要个手册2.0的不给,只给3.0的.而且态度角度***钻,想尽一切办法让你自己用不了.我又不是要做打标卡,只是做个二次开发.有必要这样吗?反正我是不会推荐用户再 ...

  7. 使用 IntersectionObserver API 遇到的一些问题

    root 设指定为 document.body 时不会触发更新 See the Pen document.body and IntersectionObserver by y1j2x34 (@y1j2 ...

  8. 使用scrollIntoView 使某元素滚动到指定位置

    var el = document.getElementById('A'); el.scrollIntoView('true'); 知识: element.scrollIntoView(); // 使 ...

  9. .net Core使用Knife4jUI更换Swagger皮肤

    Knife4j的前身是swagger-bootstrap-ui,前身swagger-bootstrap-ui是一个纯swagger-ui的ui皮肤项目 官网实战指南:https://doc.xiaom ...

  10. python的elasticsearch模块

    参考 https://www.cnblogs.com/tianzhh/articles/13542239.html