聊聊并发编程——Condition

news2024/11/24 4:31:15

目录

一.synchronized + wait/notify/notifyAll = 线程通信

二.Lock + Condition 实现线程通信

三.Condition实现通信分析

四.JUC工具类的示例


一.synchronized + wait/notify/notifyAll = 线程通信

关于线程间的通信,简单举例下:

1.创建ThreadA传入共享资源对象获取锁,执行业务后wait释放锁。

public class ThreadA extends Thread{
    private Object lock;
    public  ThreadA(Object lock){
        this.lock = lock;
    }
    @Override
    public void run() {
        synchronized (lock) {
            System.out.println("ThreadA start");
            try {
                lock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("ThreadA end");
        }
    }
}

2.创建ThreadB获取共享资源对象的锁,执行notify执行业务后会唤醒等待队列中的线程。

public class ThreadB extends Thread{
    private Object lock;
    public ThreadB(Object lock){
        this.lock = lock;
    }
    @Override
    public void run() {
        synchronized (lock) {
            System.out.println("ThreadB start");
            lock.notify();
            System.out.println("ThreadB end");
        }
    }
}

3.创建A线程B线程验证,执行结果:

public class WaitNotify {
    public static void main(String[] args) {
        Object lock = new Object();
        ThreadA threadA = new ThreadA(lock);
        threadA.start();
​
        ThreadB threadB = new ThreadB(lock);
        threadB.start();
    }
}

执行结果:

线程间wait、notify通信的流程分析如下所示:

二.Lock + Condition 实现线程通信

Condition定义了等待/通知两种类型的方法,当前线程调用这些方法时,需要提前获取到 Condition对象关联的锁。Condition对象是由Lock对象(调用Lock对象的newCondition()方法)创 建出来的,换句话说,Condition是依赖Lock对象的。

public class ConditionWait implements Runnable{
    private Lock lock;
​
    private Condition condition;
​
    public ConditionWait(Lock lock, Condition condition) {
        this.lock = lock;
        this.condition = condition;
    }
​
    @Override
    public void run() {
        lock.lock();
        try {
            System.out.println("start - ConditionWait...");
            condition.await();
            System.out.println("end - ConditionWait");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
public class ConditionNotify implements Runnable{
    private Lock lock;
    private Condition condition;
​
    public ConditionNotify(Lock lock, Condition condition) {
        this.lock = lock;
        this.condition = condition;
    }
​
    @Override
    public void run() {
        lock.lock();
        try {
            System.out.println("start - ConditionNotify...");
            condition.signal();
            System.out.println("end - ConditionNotify...");
        } finally {
            lock.unlock();
        }
    }
}
public class ConditionCommunication {
    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        new Thread(new ConditionWait(lock, condition), "await").start();  // 1
        new Thread(new ConditionNotify(lock, condition), "signal").start(); // 2
    }
}

输出结果:

如果把1和2顺序交换,ConditionWait的唤醒就会一直阻塞。输出结果:

三.Condition实现通信分析

线程 awaitThread 先通过 lock.lock()方法获取锁成功 后调用了 condition.await 方法进入等待队列,而另一个 线程 signalThread 通过 lock.lock()方法获取锁成功后调用 了 condition.signal 或者 signalAll 方法,使得线程 awaitThread 能够有机会移入到同步队列中,当其他线程释放 lock 后使得线程 awaitThread 能够有机会获取 lock,从而使得线程 awaitThread 能够从 await 方法中退出执行后续操作。如果 awaitThread 获取 lock 失败会直 接进入到同步队列。

阻塞:await()方法中,在线程释放锁资源之后,如果节点 不在 AQS 等待队列,则阻塞当前线程,如果在等待队 列,则自旋等待尝试获取锁 释放:signal()后,节点会从 condition 队列移动到 AQS 等待队列,则进入正常锁的获取流程。

四.JUC工具类的示例
  1. CountDownLatch(倒计数门栓)

    • 用途:CountDownLatch用于等待一个或多个线程完成某个操作。它初始化一个计数器,然后一个或多个线程等待这个计数器变为零,一旦变为零,等待的线程被唤醒。

    • 示例:常见于主线程等待多个工作线程全部完成后再执行的场景。

    CountDownLatch latch = new CountDownLatch(3); // 初始化计数器为3
    // 启动三个工作线程
    new Thread(() -> {
        // 执行任务
        latch.countDown(); // 减少计数器
    }).start();
    ​
    // 其他两个线程类似
    ​
    latch.await(); // 主线程等待计数器变为0
  2. CyclicBarrier(循环屏障)

    • 用途:CyclicBarrier用于多个线程互相等待,直到所有线程都到达某个屏障点,然后同时执行下一步操作。它可重复使用,因此在每个线程完成后,可以重复使用CyclicBarrier等待下一轮。

    • 示例:常见于多个线程同时进行某个任务,然后在某个点同步结果。

    CyclicBarrier barrier = new CyclicBarrier(3); // 初始化屏障为3
    // 启动三个工作线程
    new Thread(() -> {
        // 执行任务
        barrier.await(); // 等待其他线程到达屏障
    }).start();
    ​
    // 其他两个线程类似
  3. Semaphore(信号量)

    • 用途:Semaphore用于控制对某一资源的访问线程数。它维护一个计数器,每次线程访问资源时,计数器减一,当计数器为零时,其他线程需要等待。

    • 示例:常见于限制同时访问某一资源的线程数量的场景。

    Semaphore semaphore = new Semaphore(3); // 初始化信号量为3,允许3个线程同时访问
    // 启动多个线程尝试访问资源
    new Thread(() -> {
        try {
            semaphore.acquire(); // 获取资源
            // 执行任务
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release(); // 释放资源
        }
    }).start();
    ​
    // 其他线程类似
  4. Exchanger(交换器)

    • 用途:Exchanger用于两个线程之间交换数据,每个线程将数据放入Exchanger后等待,当两个线程都到达时,它们可以交换数据然后继续执行。

    • 示例:常见于两个线程之间协同工作,互相交换数据的场景。

    Exchanger<String> exchanger = new Exchanger<>();
    // 启动两个线程,交换数据
    new Thread(() -> {
        try {
            String data = "Thread A data";
            exchanger.exchange(data); // 等待交换数据
            // 处理对方线程的数据
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
    ​
    // 另一个线程类似

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

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

相关文章

获取dom元素

<button type"button" click"greet">count is {{ count }}</button>function greet(event) {if (event) {console.log(event)console.log(event.target)console.log(event.target.tagName)} } 很明显没传参数&#xff0c;但是获取到了相应的值…

JIT介绍

JIT全称&#xff1a;Just in time。中文译为&#xff1a;即时的、实时的。 JVM中的这项技术名为&#xff1a;实时编译技术&#xff0c;也叫即时编译技术。就是在java程序运行的过程中&#xff0c;将字节码编译为机器码运行在本地&#xff0c;而不是通过JVM解释运行&#xff08;…

微信公众号网页授权登录获取用户基本信息

概述 微信公众号网页授权登录后微信获取用户基本信息&#xff0c;部署即可运行完整demo 详细 一、前言 &#xff08;1&#xff09;适合人群 1&#xff0c;JAVA服务端开发人员 2&#xff0c;初级人员开发人员 3&#xff0c;了解spring springboot maven 3&#xff0c;了…

结构型设计模式——桥接模式

摘要 桥接模式(Bridge pattern): 使用桥接模式通过将实现和抽象放在两个不同的类层次中而使它们可以独立改变。 一、桥接模式的意图 将抽象与实现分离开来&#xff0c;使它们可以独立变化。 二、桥接模式的类图 Abstraction: 定义抽象类的接口Implementor: 定义实现类接口 …

蓝桥杯 题库 简单 每日十题 day12

01 列名 问题描述 在Excel中&#xff0c;列的名称使用英文字母的组合。前26列用一个字母&#xff0c;依 次为A到Z&#xff0c;接下来2626列使用两个字母的组合&#xff0c;依次为AA到zz. 请问第2022列的名称是什么&#xff1f; 答案提交 这是一道结果填空的题&#xff0c;你只…

缓存一致性(cache coherency)解决方案:MESI 协议状态转换详解

MESI 协议 一&#xff0c;MESI状态释义二&#xff0c;MESI状态转换1 Invalid after Reset2, Invalid > Exclusive3, Exclusive > Modified4 Modified > Shared, Invalid > Shared5 Shared > Invalid, Shared > Modified 三&#xff0c;状态转换场景总结Inval…

最小生成树 | 市政道路拓宽预算的优化 (Minimum Spanning Tree)

任务描述&#xff1a; 市政投资拓宽市区道路&#xff0c;本着执政为民&#xff0c;节省纳税人钱的目的&#xff0c;论证是否有必要对每一条路都施工拓宽&#xff1f; 这是一个连问带答的好问题。项目制学习可以上下半场&#xff0c;上半场头脑风暴节省投资的所有可行的思路&a…

因果引擎(Causal Engine)是基于因果推理的人工智能系统

因果引擎(Causal Engine)是一种基于因果推理的人工智能系统。 其关键思想是通过学习事件之间的因果关系,对环境进行模型化和推理,从而指导AI系统采取行动。 因果引擎的主要特征包括: 建立因果图(Causal Graph):通过统计方法学习不同事件之间的因果关系,构建表示这些因果关系的…

基于微信小程序的游戏账号交易买卖平台设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

通过 Azure 日志分析加强云安全

Microsoft Azure 云服务在安全日志存储、访问、可伸缩性、降低成本和易于部署方面提供了巨大的优势&#xff0c;因此在企业中很受欢迎。 Microsoft Azure 日志记录工具&#xff08;如 Log360&#xff09;可帮助管理 Azure 云基础结构中所有设备和应用程序&#xff08;如虚拟机…

Linux:nginx---web文件服务器

我这里使用的是centos7系统 nginx源码包安装 Linux&#xff1a;nginx基础搭建&#xff08;源码包&#xff09;_鲍海超-GNUBHCkalitarro的博客-CSDN博客https://blog.csdn.net/w14768855/article/details/131445878?ops_request_misc%257B%2522request%255Fid%2522%253A%25221…

Spring | 基于SpringBoot的多数据源实战 - 使用seata实现多数据源的全局事务管理

Spring | 基于SpringBoot的多数据源实战 - 使用seata实现多数据源的全局事务管理 引言1.1 多数据源的必要性1.2 多数据源的应用场景 实战演示2.1 创建实体类2.2 配置数据源2.3 实现数据源配置类2.4 配置Repository类2.5 运行与验证 事务管理与数据一致性3.1 事务管理3.2 使用Se…

长假,GPT来敲(Jué)门(Fén)

引 马上十一了&#xff0c;本拐在干了XX和XX事情以后&#xff0c;开始划水&#xff0c;欢天喜地的等放假。 然后&#xff0c;GPT4说更新了&#xff0c;据说加了一个读图的功能&#xff0c;本拐不以为然&#xff0c;不就是什么文生图&#xff0c;图生文么&#xff0c;TOOOLD。 不…

案例题-系统开发

案例题-系统开发 结构化分析方法概述面向对象分析方法真题1真题2 结构化分析方法概述 面向对象分析方法 了解一下符号就行 依赖关系&#xff1a;一个事务的变化影响另外一个事务的变化 泛化关系&#xff0c;父类子类 聚合&#xff1a;部分和整体之间的生命周期不同 组合&#x…

Cache系列直播,这次真的来了!

1、要学cache&#xff0c;一大堆一大堆待讨论的问题。例如近期的一些问题&#xff1a; L1、L2、L3 cache的替换策略是怎样的&#xff1f;什么类型的内存永远不会进L3 cache&#xff1f;L3 cache一般都是多大&#xff1f;L3 cache的组织形式一般是怎样的&#xff1f;什么是cache…

MySQL体系结构和四层架构介绍

MySQL体系结构图如下&#xff1a; 四层介绍 1. 连接层&#xff1a; 它的主要功能是处理客户端与MySQL服务器之间的连接(比如Java应用程序通过JDBC连接MySQL)。当客户端应用程序连接到MySQL服务器时&#xff0c;连接层对用户进行身份验证、建立安全连接并管理会话状态。它还处理…

医疗图像分割指标

医疗图像其中两种图像格式&#xff1a;MRI&#xff08;Magnetic Resonance Imaging&#xff0c;磁共振成像&#xff09;、CT&#xff08;Computed Tomography&#xff0c;计算机断层&#xff09;&#xff0c;常存成 .nii.gz 格式。都是 3D 的 H W L H \times W \times L HWL…

数字孪生智慧能源:风光储一体化能源中心

自“双碳”目标提出以来&#xff0c;我国能源产业不断朝着清洁低碳化、绿色化的方向发展。其中&#xff0c;风能、太阳能等可再生能源在促进全球能源可持续发展、共建清洁美丽世界中被寄予厚望。风能、太阳能具有波动性、间歇性、随机性等特点&#xff0c;主要通过转化为电能再…

jvm内存分配与回收策略

自动内存管理 解决两个问题 自动给对象分配内存 对象一般堆上分配&#xff08;而实际上也有可能经过即时编译后被拆散为标量类型并间接地在栈上分配&#xff09; 新生对象通常会分配在新生代&#xff0c;少数情况下&#xff08;例如对象大小超过一定阈值&#xff09;也可能…

[H5动画制作系列 ]变量,帧频,监听器等的生命周期基础测试

模式:按照上述抓图,actions层&#xff0c;1帧,写初始化代码,10帧写返回代码到2帧代码,2-10帧之间一直循环。1帧及10帧代码如下&#xff1a; 如果程序在1-10之间循环,会反复创建变量i,多个监听器等。所以,第一帧最好执行一次即可&#xff0c;程序在2-10帧之间一直循环。