并发编程学习(九):同步模式之顺序控制、交替打印

news2024/11/15 21:33:26

1、固定运行顺序

例如:两个线程,运行是必须先2后1打印。

1.1、Object之wait、notify版

在同步代码块中,wait开始后,CPU将释放给另一个线程使用,直到
①若wait(xxxx),则x秒后当前线程被唤醒,继续占用CPU。
②若wait(),则在使用notify(),后被唤醒当前线程。
/**
 * 固定运行顺序: 先打印2,后打印1
 */
@Slf4j(topic = "test.FixedRunningOrderThread")
public class FixedRunningOrderThread {
    private static final Object lock = new Object();
    private static boolean t2Runned = false;// 表示t2是否运行过

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            synchronized (lock) {
                while (!t2Runned) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("1");
            }
        },"t1");

        Thread t2 = new Thread(() -> {
            synchronized (lock) {
                log.debug("2");
                t2Runned = true;
                lock.notify();
            }
        },"t2");

        t1.start();
        t2.start();
    }
}

1.2、ReentrantLock之await、signal版

await、signal前需要获得锁。
await执行后,会释放锁,进入conditionObject等待。
await的线程被唤醒(或打断、或超时),重新竞争锁。
竞争锁成功后,从await后继续执行。
/**
 * 固定运行顺序: 先打印2,后打印1
 */
@Slf4j(topic = "test.FixedRunningOrderThread2")
public class FixedRunningOrderThread2 {
    private static final ReentrantLock lock = new ReentrantLock();
    private static final Condition waitConditionSet = lock.newCondition();
    private static boolean t2Runned = false;// 表示t2是否运行过

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            lock.lock();
            try {
                while (!t2Runned) {
                    try {
                        waitConditionSet.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("1");
            } finally {
                lock.unlock();
            }

        },"t1");

        Thread t2 = new Thread(() -> {
            lock.lock();
            try {
                log.debug("2");
                t2Runned = true;
                waitConditionSet.signal();
            } finally {
                lock.unlock();
            }
        },"t2");

        t1.start();
        t2.start();
    }
}

1.3、LockSupport之park、unpark版

// 暂停当前线程,暂停后,线程状态变为 WAITING
LockSupport.park();
// 恢复某个线程的运行,恢复后线程状态变为RUNNING
LockSupport.unpark(要恢复的线程对象);
/**
 * 固定运行顺序: 先打印2,后打印1
 *
 * LockSupport.park(); 暂停当前线程,暂停后,线程状态变为 WAITING
 * LockSupport.unpark(要恢复的线程对象); 恢复某个线程的运行,恢复后线程状态变为RUNNING
 */
@Slf4j(topic = "test.FixedRunningOrderThread3")
public class FixedRunningOrderThread3 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            LockSupport.park();
            log.debug("1");

        },"t1");

        Thread t2 = new Thread(() -> {
            log.debug("2");
            LockSupport.unpark(t1);
        },"t2");

        t1.start();
        t2.start();
    }
}

2、交替输出

示例:线程1输出a,线程2输出b,线程3输出c,交替输出5次。

2.1、Object之wait、notify版

/**
 * 交替输出: Object之wait、notify版
 * 输出内容:abcabcabcabcabc
 */
@Slf4j(topic = "test.FixedRunningOrderThread4")
public class FixedRunningOrderThread4 {

    public static void main(String[] args) {
        WaitNotify waitNotify = new WaitNotify(1,5);

        new Thread(() -> {waitNotify.print("a",1,2);}).start();
        new Thread(() -> {waitNotify.print("b",2,3);}).start();
        new Thread(() -> {waitNotify.print("c",3,1);}).start();
    }
}

@Slf4j(topic = "text.WaitNotify")
class WaitNotify {
    private int flag; // 等待标记
    private int loopNumber; // 循环次数

    public WaitNotify(int flag, int loopNumber) {
        this.flag = flag;
        this.loopNumber = loopNumber;
    }

    /**
     * @param str       打印内容
     * @param waitFlag  等待标记
     * @param nextFlag  下一个标记
     *
     *   线程         打印内容    标记    下个标记
     *    a             a          1        2
     *    b             b          2        3
     *    c             c          3        1
     */
    public void print(String str, int waitFlag, int nextFlag) {
        for (int i = 0; i < loopNumber; i++) {
            synchronized (this) {
                // 不是需要打印的标记,进入waitset
                while (flag != waitFlag) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 是需要打印的标记,直接打印
                System.out.print(str);
                // 将打印标识切换为下一个
                flag = nextFlag;
                // 唤醒waitset中的所有线程
                this.notifyAll();
            }
        }
    }
}

2.2、ReentrantLock之await、signal版

/**
 * 交替输出: ReentrantLock之await、signal版
 *
 * 输出内容:abcabcabcabcabc
 *
 */
@Slf4j(topic = "test.FixedRunningOrderThread5")
public class FixedRunningOrderThread5 {

    public static void main(String[] args) throws InterruptedException {
        AwaitSignal awaitSignal = new AwaitSignal(5);
        // 创建多个等待队列
        Condition conditionA = awaitSignal.newCondition();
        Condition conditionB = awaitSignal.newCondition();
        Condition conditionC = awaitSignal.newCondition();

        new Thread(() -> {awaitSignal.print("a",conditionA,conditionB);}).start();
        new Thread(() -> {awaitSignal.print("b",conditionB,conditionC);}).start();
        new Thread(() -> {awaitSignal.print("c",conditionC,conditionA);}).start();

        // 启动前,先睡眠1s,因为需等待线程a、b、c都进入等待队列; 
        // 否则可能等待队列中还没有线程,无法唤醒,直接结束了,无法打印出内容
        Thread.sleep(1000);
        
        awaitSignal.lock();// 获取锁
        try {
            System.out.println("开始打印。。。");
            // 先唤醒conditionA等待队列中的线程, 需先获得锁,才能调用signal
            conditionA.signal();
        } finally {
            awaitSignal.unlock();// 释放锁
        }
    }
}


/**
 * await前需要获得锁;
 * await执行后,会释放锁,进入waitConditionSet等待。
 * await的线程被唤醒(或打断、或超时),重新竞争锁; 竞争锁成功后,从await后继续执行。
 */
@Slf4j(topic = "text.AwaitSignal")
class AwaitSignal extends ReentrantLock {

    private int loopNumber; // 循环次数

    public AwaitSignal(int loopNumber) {
        this.loopNumber = loopNumber;
    }

    /**
     * @param str               打印内容
     * @param currentCondition  当前的等待队列
     * @param nextCondition     下一个等待队列
     */
    public void print(String str, Condition currentCondition, Condition nextCondition) {
        for (int i = 0; i < loopNumber; i++) {
            lock(); // 获取锁
            try {
                try {
                    currentCondition.await(); // 当前线程进入等待
                    System.out.print(str);    // 打印内容
                    nextCondition.signal();   // 唤醒下一个等待队列中的一个线程(先进先出)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } finally {
                unlock();// 释放锁
            }
        }
    }
}

2.3、LockSupport之park、unpark版

/**
 * 交替输出: LockSupport之park、unpark版
 * 输出内容:abcabcabcabcabc
 */
@Slf4j(topic = "test.FixedRunningOrderThread6")
public class FixedRunningOrderThread6 {
    private static Thread threadA;
    private static Thread threadB;
    private static Thread threadC;
    public static void main(String[] args) throws InterruptedException {
        ParkUnpark parkUnpark = new ParkUnpark(5);
        threadA = new Thread(() -> {parkUnpark.print("a",threadB);});
        threadB = new Thread(() -> {parkUnpark.print("b",threadC);});
        threadC = new Thread(() -> {parkUnpark.print("c",threadA);});

        threadA.start();
        threadB.start();
        threadC.start();
        System.out.println("开始打印。。。");
        LockSupport.unpark(threadA);
    }
}

/**
 * LockSupport.park(); 暂停当前线程,暂停后,线程状态变为 WAITING
 * LockSupport.unpark(要恢复的线程对象); 恢复某个线程的运行,恢复后线程状态变为RUNNING
 */
@Slf4j(topic = "text.ParkUnpark")
class ParkUnpark {
    private int loopNumber; // 循环次数
    public ParkUnpark(int loopNumber) {
        this.loopNumber = loopNumber;
    }

    /**
     * @param str               打印内容
     * @param nextThread        下一个需要唤醒的线程
     */
    public void print(String str,Thread nextThread) {
        for (int i = 0; i < loopNumber; i++) {
            LockSupport.park(); // 暂停当前线程
            System.out.print(str);
            LockSupport.unpark(nextThread); // 唤醒下一个线程
        }
    }
}

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

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

相关文章

STM32项目设计:基于stm32f103c8t6智能电梯系统

文章目录一、项目功能概述二、项目材料选择三、原理图设计四、PCB板设计五、主程序设计六、成品展示资料链接&#xff1a;待更新~ 哔哩哔哩视频链接&#xff1a;https://www.bilibili.com/video/BV17D4y1V7HG/?vd_sourcee5082ef80535e952b2a4301746491be0&#xff08;bilibili…

STM32G431——串口通信

蓝桥杯嵌入式——串口通信 目录 USART 电平标准-TTL 电平标准与 RS232 电平标准 232通信标准 USB转232 异步通信 串口配置 程序设计 重定向 串口发送函数 发送字符串 串口接收——中断 1.USART 通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异…

集成测试最全详解,看完必须懂了

什么是集成测试 集成测试&#xff08;Integration Testing&#xff09;&#xff0c;也叫组装测试或联合测试。在单元测试的基础上&#xff0c;将所有模块按照设计要求&#xff08;如根据结构图&#xff09;组装成为子系统或系统&#xff0c;进行集成测试。 集成测试&#xff…

chatgpt的一些思考

结论国内同行对chatgpt的认识是不够的&#xff0c;太轻视这个模式的颠覆性认知chatgpt是对思维过程的仿真&#xff0c;rlhf过程就是通过强化学习方式在利用人思维过程训练模型chatgpt比搜索更通用化&#xff0c;搜索是对单个点信息的匹配&#xff0c;chatgpt是对思维链一个序列…

【python】多任务编程之线程、进程知识点详细总结

目录 多任务的执行方式 进程 概念 python多进程 线程 概念 python多线程 线程同步方式 线程等待 互斥锁 死锁 线程和进程对比 多任务的执行方式 进程 概念 python多进程 Windows下的main判断process进程类import multiprocessing import time def sing():for i i…

Unix环境高级编程_进程环境_启动代码,环境变量表,进程内存结构,库

这是《UNIX环境高级编程》第7章内容&#xff0c;这篇文章记录进程所需要的环境。 4 进程环境 程序加载到内存&#xff0c;运行起来后就成为了进程。就像人活着需要生活环境&#xff08;衣食住行的环境&#xff09;一样&#xff0c;进程也需要运行环境&#xff0c;进程所需要的…

Vue组件生命周期与钩子函数

组件生命周期 ​ 组件&#xff08;组件是可复用的 Vue 实例&#xff09;从创建到销毁的过程就是组件的生命周期&#xff0c;是一个时间段。 组件生命周期钩子函数 &#xff08;vue3与vue2生命周期钩子函数略有不同&#xff0c;本文以vue2为主&#xff09; ​ VUE 提供的生命…

科研快报 | 三代测序技术-海水微生物态,助力海水微生态及微生物基因组研究

PacBio研究专题二代测序读长偏短&#xff0c;环境宏基因组样品研究受到了很大限制。作者通过三代测序对来自地中海的冬季混合海水样本进行宏基因组测序。利用PacBio Sequel II平台的超长读长明显可以提升宏基因组的组装质量&#xff0c;又能显著提升MAGs质量。研究人员通过比较…

使用和登录Linux云服务器

目录 云服务器的购买 SSH登录云服务器 云服务器的购买 我们以腾讯云为例, 其他的服务器厂商也是类似。 1. 进入腾讯云官方网站&#xff1a;学生云服务器_云校园特惠套餐 - 腾讯云 (tencent.com) 2. 登陆网站(可以使用微信登陆) 3.购买云服务器 购买最低级即可&#xff0c;对于…

python - 科研文献作图复现1

记录阅读文献过程中&#xff0c;通过python复现原文的一些脚本 想要复现的文章原图如下所示 原文链接&#xff1a; https://file.scirp.org/Html/4-2430166_82999.htm 首先&#xff0c;对于原图进行简要观察。 这是一张折线图&#xff0c;绘制了6条不同颜色的折线来表示不同…

舆情监控软件免费下载,TOOM网络舆情监控软件服务流程?

舆情监测可以帮助个人和企业了解自己的网络形象&#xff0c;提高自我评价和评价能力&#xff0c;提升自我定位和竞争力。接下来简单了解舆情监控软件免费下载&#xff0c;TOOM网络舆情监控软件服务流程? 一、舆情监控软件免费下载 请登录TOOM舆情官网获取链接 1.企业客户&a…

SpringMVC(十三):SpringMVC拦截器介绍使用

文章目录 SpringMVC拦截器介绍使用 前言 一、拦截器使用 二、拦截器内容详解 1、preHandle方法 2、postHandle方法 3、afterCompletion方法 三、多个拦截器执行顺序 SpringMVC拦截器介绍使用 前言 在之前的系列文章里&#xff0c;我们学习了过滤器的知识。过滤器的作…

ejs模板在Express框架中的集成

在上一篇内容中已经使用了pug模板&#xff0c;那么本篇就来了解一下ejs模板在Express框架中的集成使用&#xff0c;ejs模板也是常用的模板引擎&#xff0c;支持在标签内直接编写javascript代码&#xff0c;通过javascript代码就能够生成HTML页面的&#xff0c;通过本期对ejs模板…

C++字符串全排列(递归法)和(迭代法)以及next_permutation底层原理详解

目录前言next_permutation的使用实现全排列的两种算法1. 递归法(全排列方便理解记忆的方法&#xff0c;作为备用方法)实现代码(无重复元素情况)有重复元素情况2. 迭代法(next_permutation底层原理)实现代码(有无重复不影响)前言 next_permutation/prev_permutation是C STL中的…

全国青少年软件编程(Python)等级考试一级考试真题2022年12月——持续更新.....

1.关于Python语言的注释,以下选项中描述错误的是?( ) A.Python语言有两种注释方式:单行注释和多行注释 B.Python语言的单行注释以#开头 C.Python多行注释使用###来做为标记 D.注释用于解释代码原理或者用途 正确答案:C 2.下列代码执行后最有可能绘制出的图形是?(…

网络原理(TCP/IP五层协议)(三)

目录4.滑动窗口(效率机制)5.流量控制(安全机制)6.拥塞控制(安全机制)7.延迟应答(效率机制)8.捎带应答(效率机制)9.面向字节流10.TCP的异常处理4.滑动窗口(效率机制) 滑动窗口存在的意义就是在保证可靠性的前提下&#xff0c;尽量提高传输效率。 在这里可以看到&#xff0c;由于…

JSP 学生成绩管理系统myeclipse定制开发sqlserver数据库网页模式java编程jdbc

一、源码特点 JSP 学生成绩管理系统是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为SQLServer2008&#x…

layui 富文本layedit编辑、存储和回显

一、创建一个富文本编辑框 先定义一个textarea标签&#xff0c;给定一个id值&#xff0c;向页面引入layedit&#xff0c;然后调用layedit.build(id, options)构建富文本框 //官方给出的模板 <textarea id"demo" style"display: none;"></textar…

Linux的目录相关操作

目录 前言 处理目录的常见命令 cd&#xff08;change directory&#xff0c;切换目录&#xff09; pwd&#xff08;print working directory&#xff0c;显示目前所在的目录&#xff09; mkdir&#xff08;make directory&#xff0c;建立新目录&#xff09; rmdir&#x…

代码随想录算法训练营第十三天 | 第六章二叉树-理论基础,递归遍历,迭代遍历,统一迭代

一、参考资料二叉树理论基础文章讲解&#xff1a;https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 递归遍历题目链接/文章讲解/视频讲解&#xff1a;https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%8…