IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> JUC高并发编程(03) -- 线程间通信 -> 正文阅读

[Java知识库]JUC高并发编程(03) -- 线程间通信

JUC高并发编程

三、线程间通信

线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的。

3.1)线程间通信案例

两个线程,一个线程对当前数值加1,另一个线程对当前数值减1,要求用线程间通信

3.1.1)synchronized 方案

package com.study.sync;
?
//第一步 创建资源类,定义属性和操作方法
class Share {
 ? ?//初始值
 ? ?private int number = 0;
 ? ?//+1的方法
 ? ?public synchronized void incr() throws InterruptedException {
 ? ? ? ?//第二步 判断 干活 通知
 ? ? ? ?//判断:number值是否是0,如果不是0,等待
 ? ? ? ?// if (number != 0) {  --> 会产生虚假唤醒问题,即只对第一次进入的条件进行了判断,使用while判断可以避免虚假唤醒
 ? ? ? ?while (number != 0) {
 ? ? ? ? ? ?//在哪里睡,就在哪里醒
 ? ? ? ? ? ?this.wait();
 ? ? ?  }
 ? ? ? ?//干活:如果number值是0,就+1操作
 ? ? ? ?number++;
 ? ? ? ?System.out.println("当前线程名:" + Thread.currentThread().getName() + " :: " + number);
 ? ? ? ?//通知:通知其他线程
 ? ? ? ?this.notifyAll();
 ?  }
?
 ? ?//-1的方法
 ? ?public synchronized void decr() throws InterruptedException {
 ? ? ? ?//判断:number值是否是1,如果不是1,等待
 ? ? ? ?// if (number != 1) {  --> 会产生虚假唤醒问题,即只对第一次进入的条件进行了判断,使用while判断可以避免虚假唤醒
 ? ? ? ?while (number != 1) {
 ? ? ? ? ? ?this.wait();
 ? ? ?  }
 ? ? ? ?//干活:如果number值是1,就-1操作
 ? ? ? ?number--;
 ? ? ? ?System.out.println("当前线程名:" + Thread.currentThread().getName() + " :: " + number);
 ? ? ? ?//通知:通知其他线程
 ? ? ? ?this.notifyAll();
 ?  }
}
?
public class ThreadDemo1 {
 ? ?//第三步 创建多个线程,调用资源类的操作方法
 ? ?public static void main(String[] args) {
 ? ? ? ?Share share = new Share();
 ? ? ? ?//创建线程
 ? ? ? ?// 创建线程 AA
 ? ? ? ?new Thread(() -> {
 ? ? ? ? ? ?for (int i = 1; i <= 10; i++) {
 ? ? ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ? ? ?share.incr(); //+1
 ? ? ? ? ? ? ?  } catch (InterruptedException e) {
 ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }, "AA").start();
 ? ? ? ?// 创建线程 BB
 ? ? ? ?new Thread(() -> {
 ? ? ? ? ? ?for (int i = 1; i <= 10; i++) {
 ? ? ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ? ? ?share.decr(); //-1
 ? ? ? ? ? ? ?  } catch (InterruptedException e) {
 ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }, "BB").start();
 ? ? ? ?// 创建线程 CC
 ? ? ? ?new Thread(() -> {
 ? ? ? ? ? ?for (int i = 1; i <= 10; i++) {
 ? ? ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ? ? ?share.incr(); //+1
 ? ? ? ? ? ? ?  } catch (InterruptedException e) {
 ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }, "CC").start();
 ? ? ? ?// 创建线程 DD
 ? ? ? ?new Thread(() -> {
 ? ? ? ? ? ?for (int i = 1; i <= 10; i++) {
 ? ? ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ? ? ?share.decr(); //-1
 ? ? ? ? ? ? ?  } catch (InterruptedException e) {
 ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }, "DD").start();
 ?  }
}
输出:

com.study.sync.ThreadDemo1
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:CC :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:CC :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:AA :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0

3.1.2)Lock 方案

package com.study.lock;
?
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
?
//第一步 创建资源类,定义属性和操作方法
class Share {
 ? ?private int number = 0;
?
 ? ?//创建Lock
 ? ?private Lock lock = new ReentrantLock();
 ? ?private Condition condition = lock.newCondition();
?
 ? ?//+1 方法
 ? ?public void incr() throws InterruptedException {
 ? ? ? ?//上锁
 ? ? ? ?lock.lock();
 ? ? ? ?try {
 ? ? ? ? ? ?//判断:number值是否是0,如果不是0,等待
 ? ? ? ? ? ?// if (number != 0) {  --> 会产生虚假唤醒问题,即只对第一次进入的条件进行了判断,使用while判断可以避免虚假唤醒
 ? ? ? ? ? ?while (number != 0) {
 ? ? ? ? ? ? ? ?condition.await();
 ? ? ? ? ?  }
 ? ? ? ? ? ?//干活:如果number值是0,就+1操作
 ? ? ? ? ? ?number++;
 ? ? ? ? ? ?System.out.println("当前线程名:" + Thread.currentThread().getName() + " :: " + number);
 ? ? ? ? ? ?//通知:通知其他线程
 ? ? ? ? ? ?condition.signalAll();
 ? ? ?  } finally {
 ? ? ? ? ? ?//解锁
 ? ? ? ? ? ?lock.unlock();
 ? ? ?  }
 ?  }
?
 ? ?//-1 方法
 ? ?public void decr() throws InterruptedException {
 ? ? ? ?//上锁
 ? ? ? ?lock.lock();
 ? ? ? ?try {
 ? ? ? ? ? ?//判断:number值是否是1,如果不是1,等待
 ? ? ? ? ? ?// if (number != 1) {  --> 会产生虚假唤醒问题,即只对第一次进入的条件进行了判断,使用while判断可以避免虚假唤醒
 ? ? ? ? ? ?while (number != 1) {
 ? ? ? ? ? ? ? ?condition.await();
 ? ? ? ? ?  }
 ? ? ? ? ? ?//干活:如果number值是1,就-1操作
 ? ? ? ? ? ?number--;
 ? ? ? ? ? ?System.out.println("当前线程名:" + Thread.currentThread().getName() + " :: " + number);
 ? ? ? ? ? ?//通知:通知其他线程
 ? ? ? ? ? ?condition.signalAll();
 ? ? ?  } finally {
 ? ? ? ? ? ?//解锁
 ? ? ? ? ? ?lock.unlock();
 ? ? ?  }
 ?  }
}
?
public class ThreadDemo2 {
 ? ?public static void main(String[] args) {
 ? ? ? ?Share share = new Share();
 ? ? ? ?// 创建线程 AA
 ? ? ? ?new Thread(() -> {
 ? ? ? ? ? ?for (int i = 1; i <= 10; i++) {
 ? ? ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ? ? ?// 调用 +1 方法
 ? ? ? ? ? ? ? ? ? ?share.incr();
 ? ? ? ? ? ? ?  } catch (InterruptedException e) {
 ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }, "AA").start();
 ? ? ? ?// 创建线程 BB
 ? ? ? ?new Thread(() -> {
 ? ? ? ? ? ?for (int i = 1; i <= 10; i++) {
 ? ? ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ? ? ?// 调用 -1 方法
 ? ? ? ? ? ? ? ? ? ?share.decr();
 ? ? ? ? ? ? ?  } catch (InterruptedException e) {
 ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }, "BB").start();
 ? ? ? ?// 创建线程 CC
 ? ? ? ?new Thread(() -> {
 ? ? ? ? ? ?for (int i = 1; i <= 10; i++) {
 ? ? ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ? ? ?// 调用 +1 方法
 ? ? ? ? ? ? ? ? ? ?share.incr();
 ? ? ? ? ? ? ?  } catch (InterruptedException e) {
 ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }, "CC").start();
 ? ? ? ?// 创建线程 DD
 ? ? ? ?new Thread(() -> {
 ? ? ? ? ? ?for (int i = 1; i <= 10; i++) {
 ? ? ? ? ? ? ? ?try {
 ? ? ? ? ? ? ? ? ? ?// 调用 -1 方法
 ? ? ? ? ? ? ? ? ? ?share.decr();
 ? ? ? ? ? ? ?  } catch (InterruptedException e) {
 ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }, "DD").start();
 ?  }
?
}

输出:

com.study.lock.ThreadDemo2
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:AA :: 1
当前线程名:BB :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0
当前线程名:CC :: 1
当前线程名:DD :: 0

3.2)多线程编程步骤

  1. 创建资源类,在资源类中创建属性和操作方法
  2. 在资源类中操作方法【判断 、干活 、通知 】
  3. 创建多个线程,调用资源类的操作方法
  4. 防止虚假唤醒问题
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 12:26:14  更:2022-05-09 12:28:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:36:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码