java并发控制(猴子摘桃例子)

news2024/11/26 22:38:10

【问题】

有n个桃子, 猴子A每次固定摘2个,猴子B每次固定摘3个,这2只猴子不断摘桃子直到剩余桃子数量不足以摘(必须满足摘桃个数);


【1】 使用AtomicInteger(推荐)

1)利用 原子类的CAS原子函数(乐观锁)实现并发控制访问;

2)推荐; 乐观锁实现,代码简单,性能高; 

public class AtomicIntegerTest {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Object lock = new Object();
        AtomicInteger cap = new AtomicInteger(103);
        executorService.execute(new Task(cap, 2));
        executorService.execute(new Task(cap, 3));
        executorService.shutdown();
    }

    private static class Task implements Runnable {
        private AtomicInteger cap;
        private int consumeSize;
        private int takeCount = 0;

        Task(AtomicInteger cap, int consumeSize) {
            this.cap = cap;
            this.consumeSize = consumeSize;
        }

        @Override
        public void run() {
            while (take()) ;
            PrintUtils.print(Thread.currentThread().getName() + "#" + this);
        }

        boolean take() {
            if (cap.addAndGet(-consumeSize) >= 0) {
                takeCount++;
                return true;
            }
            return false;
        }

        @Override
        public String toString() {
            return "Task{" +
                    "consumeSize=" + consumeSize +
                    ", takeCount=" + takeCount +
                    '}';
        }
    }
}

【2】使用synchronized同步代码块

监视器锁内存结构:

1)用户线程访问Synchronized同步代码块获取锁流程

2)代码示例

public class SynchronizedTest {
    private static volatile Integer CAPACITY = 14;

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Object lock = new Object();
        executorService.execute(new Task( 2, lock));
        executorService.execute(new Task( 3, lock));
        executorService.shutdown();
    }

    static class Task implements Runnable {
        private int consumeSize;
        private Object lock;
        private int takeCount = 0;

        Task(int consumeSize, Object lock) {
            this.consumeSize = consumeSize;
            this.lock = lock;
        }

        @Override
        public void run() {
            while(take());
            PrintUtils.print(Thread.currentThread().getName() + "#" + this);
        }

        boolean take() {
            synchronized (lock) {
                if (CAPACITY >= consumeSize) {
                    CAPACITY -= consumeSize;
                    takeCount++;
                    return true;
                }
                return false;
            }
        }

        @Override
        public String toString() {
            return "Task{" +
                    "consumeSize=" + consumeSize +
                    ", takeCount=" + takeCount +
                    '}';
        }
    }
}
2024-06-09 10:42:56.989 pool-1-thread-1#Task{consumeSize=2, takeCount=4}
2024-06-09 10:42:56.989 pool-1-thread-2#Task{consumeSize=3, takeCount=2}

【3】使用可重入锁ReentrantLock

public class ReentrantLockTest {
    private static volatile Integer CAPACITY = 103;

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        ReentrantLock reentrantLock = new ReentrantLock();
        executorService.execute(new Task(2, reentrantLock));
        executorService.execute(new Task(3, reentrantLock));
        executorService.shutdown();
    }

    static class Task implements Runnable {
        private int consumeSize;
        private ReentrantLock reentrantLock;
        private int takeCount = 0;

        Task(int consumeSize, ReentrantLock reentrantLock) {
            this.consumeSize = consumeSize;
            this.reentrantLock = reentrantLock;
        }

        @Override
        public void run() {
            while (take()) ;
            PrintUtils.print(Thread.currentThread().getName() + "#" + this);
        }

        boolean take() {
            reentrantLock.lock(); // 加锁
            try {
                if (CAPACITY >= consumeSize) {
                    CAPACITY -= consumeSize;
                    takeCount++;
                    return true;
                }
                return false;
            } finally {
                reentrantLock.unlock(); // 解锁
            }
        }

        @Override
        public String toString() {
            return "Task{" +
                    "consumeSize=" + consumeSize +
                    ", takeCount=" + takeCount +
                    '}';
        }
    }
}


【4】 使用信号量Semaphore实现

semaphore.acquire()#信号量个数减1 和 release()#信号量个数加1 ;如信号量个数等于0,则 acquire() 阻塞;

public class SemaphoreTest {
    private static volatile Integer CAPACITY = 103;

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Semaphore semaphore = new Semaphore(1);// 信号量数量初始为1 
        executorService.execute(new Task(2, semaphore));
        executorService.execute(new Task(3, semaphore));
        executorService.shutdown();
    }

    static class Task implements Runnable {
        private int consumeSize;
        private Semaphore semaphore;
        private int takeCount = 0;

        Task(int consumeSize, Semaphore semaphore) {
            this.consumeSize = consumeSize;
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            while (take()) ;
            PrintUtils.print(Thread.currentThread().getName() + "#" + this);
        }

        boolean take() {
             // 获取信号量(信号数量减1)
            try {
                semaphore.acquire();
                if (CAPACITY >= consumeSize) {
                    CAPACITY -= consumeSize;
                    takeCount++;
                    return true;
                }
                return false;
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                semaphore.release();
            }
        }

        @Override
        public String toString() {
            return "Task{" +
                    "consumeSize=" + consumeSize +
                    ", takeCount=" + takeCount +
                    '}';
        }
    }
}
2024-06-09 14:20:18.509 pool-1-thread-2#Task{consumeSize=3, takeCount=5}
2024-06-09 14:20:18.509 pool-1-thread-1#Task{consumeSize=2, takeCount=44}

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

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

相关文章

11 深入理解Linux文件系统与日志分析

目录 11.1 深入理解Linux文件系统 11.1.1 inode与block详解 1. inode和block概述 2. inode的内容 3. inode的号码 4. inode的大小 11.1.2 硬链接与软连接 1. 硬链接 2. 软连接 11.1.3 EXT类型文件恢复 1. 编译安装extundelete 2. 模拟删除并执行恢复操作 11.1.4 xfs类型文件备…

【Centos】深度解析:CentOS下安装pip的完整指南

【Centos】深度解析:CentOS下安装pip的完整指南 大家好 我是寸铁👊 总结了一篇【Centos】深度解析:CentOS下安装pip的完整指南✨ 喜欢的小伙伴可以点点关注 💝 方式1(推荐) 下载get-pip.py到本地 sudo wget https://bootstrap.p…

用python编撰一个电脑清理程序

自制一个电脑清理程序,有啥用呢?在电脑不装有清理软件的时候,可以解决自己电脑内存不足的情况。 1、设想需要删除指定文件夹中的临时文件和缓存文件。以下是代码。 import os import shutil def clean_folder(folder_path): for root,…

CleanMyMac X 4.15.4破解版含2024最新CleanMyMac激活码

CleanMyMac X 4.15.4 for Mac 2023最新中文激活版是一款mac电脑清理工具,可让您快速轻松地个性化您的 Mac 操作系统。此外,它提高了系统速度和性能,帮助你远离黑客和垃圾文件。该程序具有尖端工具和功能,能够清除Mac系统中的任何故…

利用SuperGlue算法实现跨尺度金字塔特征点的高效匹配(含py代码)

在计算机视觉领域,特征点匹配是一个基础而关键的任务,广泛应用于图像拼接、三维重建、目标跟踪等方向。传统的特征点匹配方法通常基于相同尺度下提取的特征进行匹配,然而在实际场景中,由于成像距离、分辨率等因素的差异&#xff0…

图像处理ASIC设计方法 笔记29 场景自适应校正算法

P152 7.2.3 场景自适应校正算法 (一)Scribner提出的神经网络非均匀性校正算法 非均匀性校正(Non-Uniformity Correction,简称NUC)算法是红外成像技术中非常重要的一个环节。它主要用于校正红外焦平面阵列(Infrared Focal Plane Arrays,简称IRFPA)中的固定模式噪声,以提…

《python程序语言设计》2018版第5章第46题均值和标准方差-下部(本来想和大家说抱歉,但成功了)

接上回,5.46题如何的标准方差 本来想和大家说非常抱歉各位同学们。我没有找到通过一个循环完成两个结果的代码。 但我逐步往下的写,我终于成功了!! 这是我大前天在单位找到的公式里。x上面带一横是平均值。 我不能用函数的办法…

高考后志愿填报信息采集系统制作指南

在高考的硝烟散去之后,每位学生都面临着一个重要的任务——志愿填报。老师们如何高效、准确地收集和整理这些信息,成为了一个棘手的问题。难道我们只能依赖传统的手工登记方式,忍受其繁琐和易错吗? 易查分是一个简单易用的在线工具…

基于GTX 8B10B编码的自定义PHY上板测试(高速收发器十四)

前文整理了GTX IP,完成了自定义PHY协议的收发模块设计,本文将通过光纤回环,对这些模块上板测试,首先需要编写一个用于生成测试数据的用户模块。 1、测试数据生成模块 本模块用于生成自定义PHY协议的测试数据,通过axi_…

XUbuntu24.04之ch9344(usb转串口芯片)安装驱动(二百四十五)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

DVB-S系统发射端Matlab仿真及FPGA实现

DVB标准 Digital Video Broadcasting(数字视频广播)是一个完整的数字电视解决方案,其中包括DVB-C(数字电视有线传输标准), DVB-T(数字电视地面传输标准),DVB-S&#xff…

什么是突发性耳聋?

72小时内突然发生、原因不明的感音神经性听力损失,至少在相邻的两个频率听力下降≥20dBHL。 特点: 1发生在数分钟、数小时或3天以内的听力下降; 2原因不明; 3多发生于单侧,可伴有耳鸣、耳堵塞感及耳周麻木感&#…

C#操作MySQL从入门到精通(21)——删除数据

前言: 谈到数据库,大家最容易脱口而出的就是增删改查,本文就是来详细介绍如何删除数据。 本文测试使用的数据库如下: 1、删除部分数据 使用delete 关键字,并且搭配where条件使用,否则会导致表中数据全部被删除 string sql = string.Empty;if (radioButton_DeletePart…

vivado HW_ILA

HW_ILA 描述 集成逻辑分析器(ILA)调试核心允许您执行系统内监控 通过对内核上的调试探针,在实现的设计中对信号进行处理。您可以配置 ILA核心实时触发特定硬件事件,并在 以系统速度探测。 ILA调试核心可以通过从IP目录实例化ILA核…

MyBatisPlus总结二

MybatisPlus总结一在这: MybatisPlus总结1/2-CSDN博客 六、分页查询: 6.1.介绍: MybatisPlus内置了分页插件,所以我们只需要配置一个分页拦截器就可以了,由于不同的数据库的分页的方式不一样,例如mysql和…

问题汇总:MPU6050(软件iic)

以下为个人问题汇总,排查点汇总可能大有缺陷,如有错误,欢迎指正。 排查点汇总 检查软件iic的时序操作用示波器或逻辑分析仪检查波形 无法使用逻辑分析仪进行I/O引脚波形分析 充当SDA、SCL的引脚要配置为推挽输出; 另外,逻辑分…

【全开源】安心护送非急救救护车转运平台小程序(FastAdmin+ThinkPHP+Uniap

🚑安心护送非急救救护车转运平台小程序——您的健康守护者💖 安心护送转运平台小程序是一款基于FastAdminThinkPHPUniapp开发的非急救救护车租用转运平台小程序系统,可以根据运营者的业务提供类似短途接送救护服务,重症病人转运服…

一文学会Spring 实现事务,事务的隔离级别以及事务的传播机制

目录 一.Spring (Spring Boot) 实现事务 1.通过代码的方式手动实现事务 (手动档的车) 2.通过注解的方式实现声明式事务 (自动挡的车) 二.事务的4大特性(ACID) 三.事务的隔离级别 ①Mysql的事务隔离级别: ②Spring的事务隔离级别: 四.事务的传播机制 ①事务传播机制的概…

Git配置 安装及使用

团队开发的神 找工作必备 环境变量 配置好环境后 打开终端环境 winr cmd 我习惯在桌面打开,然后进入相应的文件夹 (文件夹结构) (个人感觉能用cmd不用git,cmd更好用一些) 进入对应的文件夹 填写自己对…

Valgo,类型安全,表达能⼒强的go验证器

valgo 是一个为 Go 语言设计的类型安全、表达性强且可扩展的验证库。该库的特点包括: github.com/cohesivestack/valgo 类型安全:利用 Go 语言的泛型特性(从 Go 1.18 版本开始支持),确保验证逻辑的类型安全。表达性&a…