java多线程 线程交替执行(同步)的各种实现方案

目录

  • java多线程 线程交替执行(同步)的各种实现方案
    • 需求
  • 指定具体执行顺序
    • 实现一:wait_notify机制 + Thread标志位
    • 实现二:lock_condition机制 + Thread标志位
    • 实现三:semaphore信号量
  • 不指定具体执行顺序,只交替执行
    • 实现一:synchronized和wait、notify实现
    • 实现二:lock和condition实现
  • 总结

java多线程 线程交替执行(同步)的各种实现方案

需求

有两个线程,A线程内容是输出数字1到26,B线程内容是输出字母a-z,

要求A B 线程交替执行,最终输出如下图所示

在这里插入图片描述

指定具体执行顺序

要求A B 线程交替执行,并且必须是A线程先执行,B后执行

解决思路:初始指定一个标志位,标记哪个线程可以运行,只要当前标志位不是当前线程(不满足运行条件),就一直等待

伪代码

线程A{while(满足当前线程的运行条件)不满足,则直接释放锁并进入wait状态执行当前线程内容通知下一个执行的线程,让其运行条件为true
}

实现一:wait_notify机制 + Thread标志位

实现思路:

  • 用标志位Thread标识哪个先执行
  • 线程A:只要标志位不是A就不满足运行条件,就等待;否则才执行内容,并切换Thread为下一个要执行的线程B
  • 线程A:只要标志位不是B就不满足运行条件,就等待;否则才执行内容,并切换Thread为下一个要执行的线程A

拓展:如果是三个线程交替,只需要让B线程执行完后把threadName标记为C,然后让C线程执行完后把threadName标记为A即可

public class AlternateThreads {private static final Object lock = new Object();private static String threadName = "A";public static void main(String[] args) {Thread threadA = new Thread(() -> {synchronized (lock) {for (int i = 1; i <= 26; i++) {//threadName只要不是线程A,就等待while (threadName!="A") {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.print(i + " ");threadName = "B";lock.notify();}}});Thread threadB = new Thread(() -> {synchronized (lock) {for (char c = 'a'; c <= 'z'; c++) {//threadName只要不是线程A,就等待while (threadName!="B") {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.print(c + " ");threadName = "A";lock.notify();}}});threadA.start();threadB.start();}
}

实现二:lock_condition机制 + Thread标志位

实现思路:和wait_notiy实现的基本一致,也是,只不过wait变成了await,notify变成了signal

拓展:如果是三个线程交替,只需要让B线程执行完后把threadName标记为C,然后让C线程执行完后把threadName标记为A即可

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class AlternateThreads {private static Lock lock = new ReentrantLock();private static Condition condition = lock.newCondition();private static String threadName = "A";/**目标:交替执行的基础上,必须先执行A,再执行B* 方案:lock_condition机制 + Thread标志位* 实现思路:和我wait_notiy实现的基本一致,也是,只不过wait变成了await,notify变成了signal* @param args*/public static void main(String[] args) {Thread threadA = new Thread(() -> {try {lock.lock();for (int i = 1; i <= 26; i++) {while (threadName!="A") {condition.await();}System.out.print(i + " ");threadName = "B";condition.signal();}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}});Thread threadB = new Thread(() -> {try {lock.lock();for (char c = 'a'; c <= 'z'; c++) {while (threadName!="B") {condition.await();}System.out.print(c + " ");threadName = "A";condition.signal();}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}});threadA.start();threadB.start();}
}

实现三:semaphore信号量

实现思路:

  • 线程A:开始执行时,先申请信号量s1,执行结束后,再释放信号量s2,让B结束等待;
  • 线程B:开始执行时,先申请信号量s2,执行结束后,再释放信号量s1,让A结束等待;
  • 初始化:设置线程A对应的信号量初始为1,B线程对应信号量为0,保证A先执行

拓展:如果是三个线程交替,只需要让B线程执行完后release信号量C,然后让C线程执行完后release信号量A

public class AlternateThreads {private static Semaphore semaphoreA = new Semaphore(1);private static Semaphore semaphoreB = new Semaphore(0);public static void main(String[] args) {Thread threadA = new Thread(() -> {for (int i = 1; i <= 26; i++) {try {semaphoreA.acquire();//申请信号量ASystem.out.print(i + " ");semaphoreB.release();//通知B可以运行了} catch (InterruptedException e) {e.printStackTrace();}}});Thread threadB = new Thread(() -> {for (char c = 'a'; c <= 'z'; c++) {try {semaphoreB.acquire();//申请信号量BSystem.out.print(c + " ");semaphoreA.release();//通知A可以运行了} catch (InterruptedException e) {e.printStackTrace();}}});threadA.start();threadB.start();}
}

不指定具体执行顺序,只交替执行

要求:如果不要求A和B哪个先执行,只要求A和B交替执行

解决思路:保证互斥,直接执行内容,再notify唤醒其它线程,最后自己再释放锁进入wait状态

伪代码

线程A{while(是否满足当前线程A的运行条件?)不满足,则直接释放锁并进入wait执行当前线程内容通知下一个执行的线程B,让其运行条件为true
}

为什么这样不能保证哪个先执行?

因为各个线程只要竞争到锁,就会直接运行,后续再wait,而不是先判断是否要wait

实现一:synchronized和wait、notify实现

public class ThreadSyn {//实现方式一,synchronized和wait、notify实现,不保证先执行哪一个public static void test1() {Object lock = new Object();boolean flag = false;Thread a = new Thread(() -> {synchronized (lock) {for (int i = 1; i <= 26; i++) {//直接运行System.out.print(i + " ");try {//先唤醒,再阻塞lock.notify();lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}lock.notify();//结束后唤醒,防止死锁}});Thread b = new Thread(() -> {synchronized (lock) {for (char ch = 'a'; ch <= 'z'; ch++) {//直接运行System.out.print(ch + " ");try {//先唤醒,再阻塞lock.notify();lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}lock.notify();//结束后唤醒,防止死锁}});a.start();b.start();}

实现二:lock和condition实现

    //实现方式二:lock和condition实现,A B交替执行,也不确定先执行的是哪个,只能确保轮流执行public static void test2() {Lock lock = new ReentrantLock();Condition condition_A = lock.newCondition();Condition condition_B = lock.newCondition();Thread a = new Thread(() -> {lock.lock();for (int i = 1; i <= 26; i++) {//直接运行System.out.print(i + " ");try {//先唤醒,再阻塞condition_B.signal();//唤醒线程Bcondition_A.await();//等待条件A} catch (InterruptedException e) {e.printStackTrace();}}condition_B.signal();//执行完for循环后需释放最后在等待的B线程,防止死锁lock.unlock();});Thread b = new Thread(() -> {lock.lock();for (char ch = 'a'; ch <= 'z'; ch++) {System.out.print(ch + " ");//执行线程操作try {condition_A.signal();//唤醒线程Acondition_B.await();//等待条件B} catch (InterruptedException e) {e.printStackTrace();}}condition_A.signal();//执行完for循环后需释放最后在等待的A线程,防止死锁lock.unlock();});a.start();b.start();}

总结

如果想要指定执行顺序,则需要用信号量,或者自己实现一个标志位去模拟信号量

如果不需要指定执行顺序,则谁先竞争到锁就谁先执行,执行完后唤醒另一个线程,再进入wait状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/11777.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Electron + GitHub Actions | 自动化流程详解(下)

自动化部署 上篇介绍了 Electron Forge 打包应用教程。在实际开发中&#xff0c;自动化是提升效率和产出质量的关键。本篇我们将详细介绍如何将构建和发布 Electron 应用的过程自动化。 代码挂在 GitHub 仓库上&#xff0c;如果有帮助&#xff0c;记得给仓库点个赞&#xff1a…

MQTT学习(一)

MQTT是一种与HTTP类似的应用层协议。 在某些物联网应用中&#xff0c;MQTT优于HTTP。 首先&#xff0c;HTTP是用于客户端服务器计算的以文档为中心的请求-响应协议。 HTTP是万维网的基础&#xff0c;但它不是专门为机器之间通信而设计的。 MQTT是一种机器对机器、以数据为中…

Python pyqtgraph库:高效可视化数据的利器

更多Python学习内容&#xff1a;ipengtao.com 在数据科学和工程领域&#xff0c;数据可视化是一项非常重要的任务。Python pyqtgraph库是一个功能强大的数据可视化工具&#xff0c;可以帮助用户快速、高效地可视化各种类型的数据&#xff0c;包括实时数据、大数据集和3D数据等。…

英伟达解码性能NVDEC

如果你能打开官网&#xff0c;请看这里&#xff1a; NVDEC Application Note 下面是摘录&#xff1a;

STL---排序模板参数

map 对map进行排序 首先一定要注意map模板类的第三个模板参数&#xff0c;这个参数决定元素按键值升序或者降序在map中的存储方式&#xff1a; 默认&#xff1a;less<key>升序----- < -----第一个小于取第一个 可设置&#xff1a;greater<key>降序-------…

VC 编程开发中的 封装类 :log日志类 和SQL server 操作类 源代码

VC 编程开发中的 封装类 &#xff1a;日志类 和SQL server 操作类 源代码 在VC&#xff08;Visual C&#xff09;开发中&#xff0c;日志文件输出是一个至关重要的环节&#xff0c;它对于程序调试、问题排查以及系统监控等方面都具有不可替代的作用。以下是对日志文件输出在VC开…

ASP.NET仪器设备管理系统设计与实现

摘 要 文中以某中小型企业的设备管理为例&#xff0c;对设备管理系统的设计与应用进行研究&#xff0c;旨在通过设备管理系统提高内部设备的利用率及实现其最大的经济效益。文中首先对设备管理的现状及其重要性进行了分析&#xff0c;分析实现设备管理信息系统的必要性与可行…

如何在windows server下安装mysql5.7数据库,并使用Navicat Premium 15可视化工具新建数据库并读取数据库信息。

如何在windows server下安装mysql5.7数据库&#xff1f; MySQL :: Download MySQL Community Server (Archived Versions)https://downloads.mysql.com/archives/community/点击↑&#xff0c;然后选择对应版本和平台↓下载 将下载后的安装包放入固定目录&#xff08;这里以D:…

更适合户外使用的开放式耳机,佩戴舒适音质悦耳,虹觅HOLME NEO体验

随着气温的逐渐升高&#xff0c;不管是在室内工作娱乐&#xff0c;还是到户外运动健身&#xff0c;戴上一款合适的耳机都会帮我们隔绝燥热与烦闷&#xff0c;享受音乐与生活。现在市面上的耳机类型特别多&#xff0c;我很喜欢那种分体式的开放耳机&#xff0c;感觉这种耳机设计…

从头开始学Spring—02基于XML管理bean

目录 1.实验一&#xff1a;入门案例 2.实验二&#xff1a;获取bean 3.实验三&#xff1a;依赖注入之setter注入 4.实验四&#xff1a;依赖注入之构造器注入 5.实验五&#xff1a;特殊值处理 6.实验六&#xff1a;为类类型属性赋值 7.实验七&#xff1a;为数组类型属性赋值…

掌握决策之道:层次分析法(AHP)的步骤、应用与局限性

目录 一、层次分析法简介 举一个小例子&#xff1a; 评价类问题可用打分解决&#xff0c;比如&#xff1a;小华高考结束后&#xff0c;在华科和武大两所学校之间做抉择。 评价类问题可用打分解决 二、层次分析法的步骤 &#xff08;一&#xff09;一道引出层次分析法的例…

如何在创建之前检测 Elasticsearch 将使用哪个索引模板

作者&#xff1a;来自 Elastic Musab Dogan 概述 Elasticsearch 提供两种类型的索引模板&#xff1a;旧&#xff08;legacy&#xff09;索引模板和可组合 (composable) 索引模板。 Elasticsearch 7.8 中引入的可组合模板旨在替换旧模板&#xff0c;两者仍然可以在 Elasticsear…

深入理解MVCC与Read View:并发控制的关键要素

MVCC MVCC的几个问题1.update、insert、select和delete如何在MVCC中维护版本链&#xff1f;2.select读取&#xff0c;是读取最新的版本呢&#xff1f;还是读取历史版本&#xff1f;3.当前读和快照读4.那为什么要有隔离级别呢&#xff1f;5.如何保证&#xff0c;不同的事务&…

Automa:一键自动化,网页数据采集与工作流程优化专家

Automa&#xff1a;解锁自动化浏览器潜能&#xff0c;赋能工作效率&#xff0c;让复杂任务变得简单- 精选真开源&#xff0c;释放新价值。 概览 Automa是一款创新的网页自动化工具&#xff0c;专为寻求提升工作效率、简化数据收集过程的现代工作者设计。它融合了先进的数据抓取…

模板:vector(顺序表容器)

1.构造函数 explicit vector (const allocator_type& alloc allocator_type()); //默认构造函数explicit vector (size_type n, const value_type& val value_type(),const allocator_type& alloc allocator_type()); //n个重复的valtemplate <class Input…

Angular入门

Angular版本&#xff1a;Angular 版本演进史概述-天翼云开发者社区 - 天翼云 安装nodejs&#xff1a;Node.js安装与配置环境 v20.13.1(LTS)-CSDN博客 Angular CLI是啥 Angular CLI 是一个命令行接口(Angular Command Line Interface)&#xff0c;是开发 Angular 应用的最快、最…

大模型时代下两种few shot高效文本分类方法

介绍近年(2022、2024)大语言模型盛行下的两篇文本分类相关的论文&#xff0c;适用场景为few shot。两种方法分别是setfit和fastfit&#xff0c;都提供了python的包使用方便。 论文1&#xff1a;Efficient Few-Shot Learning Without Prompts 题目&#xff1a;无需提示的高效少…

深入了解 MyBatis 插件:定制化你的持久层框架

序言 MyBatis 是一个流行的 Java 持久层框架&#xff0c;它提供了简单而强大的数据库访问功能。然而&#xff0c;有时候我们需要在 MyBatis 中添加一些自定义的功能或行为&#xff0c;来满足特定的需求。这时&#xff0c;MyBatis 插件就发挥了重要作用。本文将深入探讨 MyBati…

An 2024下载

An2024下载&#xff1a; 百度网盘下载https://pan.baidu.com/s/1cQQCFL16OUY1G6uQWgDbSg?pwdSIMS Adobe Animate 2024&#xff0c;作为Flash技术的进化顶点&#xff0c;是Adobe匠心打造的动画与交互内容创作的旗舰软件。这款工具赋予设计师与开发者前所未有的创意自由&#x…

HIVE卡口流量需求分析

HIVE卡口流量需求分析 目录 HIVE卡口流量需求分析 1.创建表格 插入数据 2.需求 3.总结&#xff1a; 1.创建表格 插入数据 CREATE TABLE learn3.veh_pass( id STRING COMMENT "卡口编号", pass_time STRING COMMENT "进过时间", pass_num int COMMENT …