线程间通信

多线程编程步骤

  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. 弹框tabel树

    <template> <div> <el-dialog :title="title" :visible.sync="dialogVisibl ...

  2. Web_Servlet之间请求转发

    Servlet2 @WebServlet(urlPatterns = "/aa") public class JspService extends HttpServlet { pr ...

  3. 关于uniapp图片默认的空隙处理方案

    display:block; 或者 display:flex;

  4. FHAdmin实战获取shell

    又是一个愉快的摸鱼的一天,闲来无事去逛先知社区突然看到了一篇名为shrio权限实战绕过的文章(https://xz.aliyun.com/t/8311),这时不禁突然 回想起来之前看到过的一个微信公众 ...

  5. 借助5G智能网关实现无人化智慧农业应用

    发展智慧农业是新时代的必由之路.依托5G+物联网技术赋能农业生产,能够实现更少的人员需求,更大面积的综合土地管理,更实时精细的生产环境监测,更智能的生产自主管控.5G技术正以其广连接.低时延的优势,助 ...

  6. WIn环境基于vs编辑器,Qt应用申请管理员权限的解决方法(转载)

    原文章地址:https://blog.csdn.net/weixin_38416696/article/details/103879377 基本按照那个文章的操作.基本可以了. 唯一问题就是那个vs的 ...

  7. <context:component-scan/>和<mvc:annotation-driven/>的区别

    1 <context:annotation-config/> 如果你想使用@Autowired注解,那么就必须事先在 spring 容器中声明 AutowiredAnnotationBea ...

  8. Linux Broadcom Bluetooth BCM43142A0 蓝牙驱动安装

    Linux Broadcom Bluetooth BCM43142A0 蓝牙驱动安装 想转到Linux,奈何蓝牙鼠标不识别. 经历了4个发行版的努力(Linux Mint,Pop!OS,OpenSus ...

  9. 第二章启动引导器GRUB2

    第二章启动引导器GRUB2grub的配置文件路径:vim /boot/grub2/grub.cfg (不建议直接编辑)vim /etc/default/grub (可编辑的文件)将编辑的操作刷新到/b ...

  10. Javaweb基础知识复习------AJAX

    AJAX相关知识复习 简而言之,就是可以用AJAX+HTML代替JSP页面,也可以进行异步交互,更新部分界面 Ajax案例 后端代码就是一个servlet文件,前端页面的代码也不是很常用,可以在下面这 ...