锁机制之 Condition 接口

news2024/12/23 9:25:53

1. 前言

本节内容主要是对 Java 锁机制之 Condition 接口进行讲解,Condition 接口是配合 Lock 接口使用的,我们已经学习过 Lock 接口的相关知识,那么接下来对 Condition 接口进行讲解。本节内容的知识点如下:

2. Condition 接口简介

定义:Condition 接口也提供了类似 Object 的监视器方法,与 Lock 配合可以实现等待 / 通知模式。Condition 可以看做是 Obejct 类的 wait ()、notify ()、notifyAll () 方法的替代品,与 Lock 配合使用。

public interface Condition {
    void await() throws InterruptedException;
    long awaitNanos(long nanosTimeout) throws InterruptedException; 
    boolean await(long time, TimeUnit unit) throws InterruptedException;
    boolean awaitUntil(Date deadline) throws InterruptedException;
    void signal();
    void signalAll();
}

等待机制方法简介

  • void await() throws InterruptedException:当前线程进入等待状态,直到被其它线程的唤醒继续执行或被中断
  • void awaitUninterruptibly():当前线程进入等待状态,直到被其它线程被唤醒
  • long awaitNanos(long nanosTimeout) throws InterruptedException:当前线程进入等待状态,直到被其他线程唤醒或被中断,或者指定的等待时间结束;nanosTimeout 为超时时间,返回值 = 超时时间 - 实际消耗时间
  • boolean await(long time, TimeUnit unit) throws InterruptedException:当前线程进入等待状态,直到被其他线程唤醒或被中断,或者指定的等待时间结束;与上个方法区别:可以自己设置时间单位,未超时被唤醒返回 true,超时则返回 false
  • boolean awaitUntil(Date deadline) throws InterruptedException:当前线程等待状态,直到被其他线程唤醒或被中断,或者指定的截止时间结束,截止时间结束前被唤醒,返回 true,否则返回 false。

通知机制方法简介

  • void signal():唤醒一个线程;
  • void signalAll():唤醒所有线程。

2.1.Condition 对象的创建

Condition 对象是由 Lock 对象创建出来的 (Lock.newCondition),换句话说,Condition 是依赖 Lock 对象的。那么我们来看看如果创建 Condition 对象。

Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();

3.ReentrantLock 与 Condition 实现生产者与消费者

场景修改

  • 创建一个工厂类 ProductFactory,该类包含两个方法,produce 生产方法和 consume 消费方法(未改变);
  • 对于 produce 方法,当没有库存或者库存达到 10 时,停止生产。为了更便于观察结果,每生产一个产品,sleep 3000 毫秒(5000 变 3000,调用地址也改变了,具体看代码);
  • 对于 consume 方法,只要有库存就进行消费。为了更便于观察结果,每消费一个产品,sleep 5000 毫秒(sleep 调用地址改变了,具体看代码);
  • 库存使用 LinkedList 进行实现,此时 LinkedList 即共享数据内存(未改变);
  • 创建一个 Producer 生产者类,用于调用 ProductFactory 的 produce 方法。生产过程中,要对每个产品从 0 开始进行编号 (新增 sleep 3000ms);
  • 创建一个 Consumer 消费者类,用于调用 ProductFactory 的 consume 方法 (新增 sleep 5000ms);
  • 创建一个测试类,main 函数中创建 2 个生产者和 3 个消费者,运行程序进行结果观察(未改变)。

以下是所有代码。

public class DemoTest {
        public static void main(String[] args) {
            ProductFactory productFactory = new ProductFactory();
            new Thread(new Producer(productFactory),"1号生产者"). start();
            new Thread(new Producer(productFactory),"2号生产者"). start();
            new Thread(new Consumer(productFactory),"1号消费者"). start();
            new Thread(new Consumer(productFactory),"2号消费者"). start();
            new Thread(new Consumer(productFactory),"3号消费者"). start();
        }
}

class ProductFactory {
    private LinkedList<String> products; //根据需求定义库存,用 LinkedList 实现
    private int capacity = 10; // 根据需求:定义最大库存 10
    private Lock lock = new ReentrantLock(false);
    private Condition p = lock.newCondition();
    private Condition c = lock.newCondition();
    public ProductFactory() {
        products = new LinkedList<String>();
    }
    // 根据需求:produce 方法创建
    public void produce(String product) {
        try {
            lock.lock();
            while (capacity == products.size()) { //根据需求:如果达到 10 库存,停止生产
                try {
                    System.out.println("警告:线程("+Thread.currentThread().getName() + ")准备生产产品,但产品池已满");
                    p.await(); // 库存达到 10 ,生产线程进入 wait 状态
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            products.add(product); //如果没有到 10 库存,进行产品添加
            System.out.println("线程("+Thread.currentThread().getName() + ")生产了一件产品:" + product+";当前剩余商品"+products.size()+"个");
            c.signalAll(); //生产了产品,通知消费者线程从 wait 状态唤醒,进行消费
        } finally {
            lock.unlock();
        }
    }

    // 根据需求:consume 方法创建
    public String consume() {
        try {
            lock.lock();
            while (products.size()==0) { //根据需求:没有库存消费者进入wait状态
                try {
                    System.out.println("警告:线程("+Thread.currentThread().getName() + ")准备消费产品,但当前没有产品");
                    c.await(); //库存为 0 ,无法消费,进入 wait ,等待生产者线程唤醒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            String product = products.remove(0) ; //如果有库存则消费,并移除消费掉的产品
            System.out.println("线程("+Thread.currentThread().getName() + ")消费了一件产品:" + product+";当前剩余商品"+products.size()+"个");
            p.signalAll();// 通知生产者继续生产
            return product;
        } finally {
            lock.unlock();
        }
    }
}

class Producer implements Runnable {
    private ProductFactory productFactory; //关联工厂类,调用 produce 方法
    public Producer(ProductFactory productFactory) {
        this.productFactory = productFactory;
    }
    public void run() {
        int i = 0 ; // 根据需求,对产品进行编号
        while (true) {
            productFactory.produce(String.valueOf(i)); //根据需求 ,调用 productFactory 的 produce 方法
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
        }
    }
}
class Consumer implements Runnable {
    private ProductFactory productFactory;
    public Consumer(ProductFactory productFactory) {
        this.productFactory = productFactory;
    }
    public void run() {
        while (true) {
            productFactory.consume();
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

上述代码结果如下图所示

 

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

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

相关文章

cookie、localStorage 和sessionStorage

文章目录Cookie1.什么是 Cookie&#xff1f;2.cookie的工作机制&#xff0c;运作流程cookie属性项3.读取cookie4.修改cookie5.删除cookielocalStorage 和sessionStorage1.生存期2.数据结构3.API 不管是 localStorage&#xff0c;还是 sessionStorage&#xff0c;可使用的API都相…

基于FPGA+MPU+MCU全自动血细胞分析仪解决方案

全自动血细胞分析仪是医院临床检验应用非常广泛的仪器之一&#xff0c;用来检测红细胞、血红蛋白、白细胞、血小板等项目。是基于电子技术和自动化技术的全自动智能设备&#xff0c;功能齐全&#xff0c;操作简单&#xff0c;依托相关计算机系统在数据处理和数据分析等方面具有…

蓝牙学习三(GAP)

1.简介 GAP&#xff08;Generic Access Profile-通用访问配置文件&#xff09;与应用层紧密相连&#xff0c;所以要想了解BLE&#xff0c;GAP是必须认识的东西。 在第一章中我们说过GAP层&#xff0c;GAP层目前主要用来进行广播、扫描和发起连接。GAP保证了不同的BLE设备可以互…

深度学习入门(7)误差反向传播计算方式及简单计算层的实现

在上一节中《深度学习入门&#xff08;6&#xff09;误差反向传播基础---计算图与链式法则》&#xff0c;我们介绍了误差反向传播的计算图与导数计算的链式法则&#xff0c;这一节主要介绍计算图中各计算节点的误差反向传播计算方式&#xff0c;以及加法与乘法层的实现。 目录…

Scala系列-4、scala中特质、柯里化、闭包等

版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。 传送门&#xff1a;大数据系列文章目录 目录scala中特质特质作为接口使用特质中放置非抽象的成员特质的模板操作特质的混入对象操作特质的执行链…

T31开发笔记: 使用FTP上传下载文件

若该文为原创文章&#xff0c;转载请注明原文出处 一、前言 最段时间&#xff0c;在开发IPC时&#xff0c;突然想到把录制好的MP4文件上传到服务器&#xff0c;考虑了一些方法&#xff0c;感觉用TFP方式比较好&#xff0c;可以下载和上传文件&#xff0c;只需要搭建一个简单的…

【Mybatis编程:修改数据(动态SQL)】

目录 1. 在AlbumMapper.java中添加抽象方法 2. 在AlbumMapper.xml中配置SQL 3. 在AlbumMapperTests.java中编写并执行测试 1. 在AlbumMapper.java中添加抽象方法 在AlbumMapper.java中添加抽象方法&#xff1a; /** * 修改相册数据 * * param album 封装了被修改的相册的…

【Mybatis编程:批量插入相册(动态SQL)】

目录 1. 书写SQL语句 2. 在AlbumMapper.java中添加抽象方法 3. 在AlbumMapper.xml中配置SQL 4. 在AlbumMapperTests.java中编写并执行测试 1. 书写SQL语句 需要执行的SQL语句大致是&#xff1a; insert into pms_album (name, description, sort) values (?,?,?), (?…

AcWing算法基础课笔记 1.基础算法

目录AcWing算法基础课笔记 1.基础算法二分排序基本思想代码归并排序基本思路代码高精度计算加法减法乘法除法前缀和一维二维AcWing算法基础课笔记 1.基础算法 二分排序 基本思想 基于分治的思想 确定哨兵xxx&#xff1a;可以取左边界&#xff0c;中间值&#xff0c;右边界&…

Docker的容器管理操作

Docker的容器管理操作Docker的容器管理操作1. 创建容器2. 启动容器3、查看容器的运行状态4、创建并启动容器5、在后台持续运行 docker run 创建的容器6、停止容器7、 删除容器8、 容器的进入9、查看容器的元数据——docker inspect10、容器日志11、宿主机和容器之间的文件复制将…

Android——FloatingActionButton使用说明以及避坑

1、简介 1.1、 com.android.support库下 compile com.android.support:design:26.0.0 1.2、material库下 com.google.android.material.floatingactionbutton.FloatingActionButton 库下 implementation com.google.android.material:material:1.1.0 官方地址&#xff1a;…

怎么有效地进行问卷发放?

进行问卷调查分为四步&#xff1a;制作问卷、发放问卷、收集问卷、分析问卷。其中&#xff0c;发放问卷起到了关键性的作用。他关乎到我们后续收集问卷是否顺利&#xff0c;收集到的问卷数据是否具备真实性和有效性。那么&#xff0c;怎么有效地进行问卷发放呢&#xff1f; 1、…

右键实现打开对应的软件

右键实现打开对应的软件前言&#xff1a;下面我以右键打开Pycharm为例子&#xff01;&#xff01;&#xff01;一、打开注册表1.1 WinR&#xff0c;输入regedit,回车二、实现右键打开特定文件的效果2.1找到路径&#xff1a;计算机\HKEY_CLASSES_ROOT\*\shell2.2 创建文件夹2.3 …

【In-Context Learning】Meta-learning via Language Model In-context Tuning

In-Context Learning是最近比较火热的方向&#xff0c;其主要针对超大规模模型&#xff08;例如1750B参数量的GPT-3模型&#xff09;&#xff0c;在只提供少量标注样本作为提示的前提下&#xff0c;即可以实现很惊艳的效果。本文将元学习引入到In-Context Learning中。 论文PDF…

企业实践开源的动机

文章来源&#xff1a;” 夜天之书 “微信公众号 作者&#xff1a;tison 随着开源软件全面占据软件供应链的各个阶段&#xff0c;商业公司开发基础软件或业务逻辑的时候&#xff0c;已经避不开对软件的使用了。经过一段时间对开源软件的使用&#xff0c;以及开源吞噬软件的趋势…

海量Redis数据库优化,vivo如何实现成本与性能的平衡

概述 随着数字化技术的创新以及时延敏感型应用的持续落地&#xff0c;越来越多的数据需要实现实时或近实时的处理&#xff0c;这推动了 Redis 等内存数据库的广泛应用。此类数据库对于内存容量有着较高的要求&#xff0c;在数据快速增长的背景下&#xff0c;大内存池构建意味着…

分布式监控平台——Zabbix

市场上常用的监控软件&#xff1a; 传统运维&#xff1a;zabbix、 Nagios云原生环境&#xff1a; Prometheus &#xff08;go语言开发的&#xff09; 一 Zabbix概述 作为一个运维&#xff0c;需要会使用监控系统查看服务器状态以及网站流量指标&#xff0c;利用监控系统的数据…

二叉树的遍历-树-数据结构和算法(Java)

1 树的遍历方式 1.1 深度优先 事实上&#xff0c;深度优先搜索属于图算法的一种&#xff0c;英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止&#xff0c;而且每个节点只能访问一次. 那么对于树来说&#xff0c;"深度优先…

使用阿里云国际版负载均衡管理多台服务器上的流量

有效处理多云服务器设置的流量和数据传输负载可能是一个复杂的过程。然而&#xff0c;这是完全必要的&#xff0c;因为业务关键型应用程序需要高度可用的解决方案来管理繁重的工作负载。阿里云服务器负载均衡器(SLB) 简化了工作负载在服务器、网络链路和其他资源之间的分配&…

[附源码]SSM计算机毕业设计闲置物品交易管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…