Java 并发编程知识总结【四】

news2024/9/24 21:27:27

5. 线程通信

5.1 Lock 接口

是什么:Lock 实现提供比使用 synchronized 方法和语句可以获得的更广泛的锁定操作。 它们允许更灵活的结构化,可能具有完全不同的属性,并且可以支持多个相关联的对象 Condition

Lock 接口的实现 ReentrantLock 可重入锁

Lock l = ...;
l.lock();
try {
    // access the resource protected by this lock
} finally {
    l.unlock();
}

synchronized 与 Lock 的区别两者区别:

  1. 首先 synchronized 是 java 内置关键字,在 jvm 层面,Lock 是个 java 类(接口)
  2. synchronized 无法判断是否获取锁的状态,Lock 可以判断是否获取到锁
  3. synchronized 会自动释放锁(a线程执行完同步代码会释放锁;b线程执行过程中发生异常会释放锁),Lock 需在 finally 中手工释放锁(unlock() 方法释放锁),否则容易造成线程死锁
  4. 用 synchronized 关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而 Lock 锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了
  5. synchronized 的锁可重入、不可中断、非公平,而 Lock 锁可重入、可判断、可公平(两者皆可)
  6. Lock 锁适合大量同步的代码的同步问题,synchronized 锁适合代码少量的同步问题。

5.2 线程通信

  1. 生产者+消费者
  2. 通知等待唤醒机制

多线程编程模板:

  • 在高内聚、低耦合的前提下,线程 操作(对外暴露的调用方法,自身的方法) 资源类

高内聚:自己应带的东西自己带着,并对外暴露(空调有制冷和制热是出厂就带着的,但是人不带着制冷和制热)

低耦合(拆分):eg:前后端分离、淘宝与顺丰之间的关系,但是淘宝内部没有与顺丰相关的、顺丰内部也没有与淘宝相关的

  • 判断 —> 干活 —> 通知
  • 防止虚假唤醒用 while
  • 注意修改标志位

案例:现在两个线程,可以操作初始值为零的一个变量,实现一个线程对该变量加1,一个线程对该变量减1,交替,来10轮。

Synchronized 实现

// 资源类
class AirConditioner {
    private int number = 0;

    public synchronized void increment() throws InterruptedException {
        // 1. 判断
        while (number != 0) {
            this.wait();
        }
        // 2. 干活
        ++number;
        SmallTool.printTimeAndThread(String.valueOf(number));
        // 3. 通知
        this.notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {
        // 1. 判断
        while (number == 0) {
            this.wait();
        }
        // 2. 干活
        --number;
        SmallTool.printTimeAndThread(String.valueOf(number));
        // 3. 通知
        this.notifyAll();
    }
}
public static void main(String[] args) {
    AirConditioner airConditioner = new AirConditioner();

    new Thread(() -> {
        for (int i = 1; i <= 10; i++) {
            try {
                airConditioner.increment();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, "A").start();

    new Thread(() -> {
        for (int i = 1; i <= 10; i++) {
            try {
                airConditioner.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, "B").start();

    new Thread(() -> {
        for (int i = 1; i <= 10; i++) {
            try {
                airConditioner.increment();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, "C").start();

    new Thread(() -> {
        for (int i = 1; i <= 10; i++) {
            try {
                airConditioner.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, "D").start();
}

Java8 新版本实现

image-20230101151808311

Condition

image-20230101152415051

代码实现

// 资源类
class AirConditioner {
    private int number = 0;

    private final Lock lock = new ReentrantLock();

    private final Condition condition = lock.newCondition();

    public void increment() {
        lock.lock();
        try {
            // 1. 判断
            while (number != 0) {
                condition.await();
            }
            // 2. 干活
            ++number;
            SmallTool.printTimeAndThread(String.valueOf(number));
            // 3. 通知
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void decrement() {
        lock.lock();
        try {
            // 1.判断
            while (number == 0) {
                condition.await();
            }
            // 2.干活
            number--;
            SmallTool.printTimeAndThread(String.valueOf(number));
            // 3.通知
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
public static void main(String[] args) {
    AirConditioner airConditioner = new AirConditioner();

    new Thread(() -> {
        for (int i = 1; i <= 10; i++) {
            airConditioner.increment();
        }
    }, "A").start();

    new Thread(() -> {
        for (int i = 1; i <= 10; i++) {
            airConditioner.decrement();
        }
    }, "B").start();

    new Thread(() -> {
        for (int i = 1; i <= 10; i++) {
            airConditioner.increment();
        }
    }, "C").start();

    new Thread(() -> {
        for (int i = 1; i <= 10; i++) {
            airConditioner.decrement();
        }
    }, "D").start();
}

5.3 线程间定制化调用通信

案例:多线程之间按顺序调用,实现A->B->C,三个线程启动,要求如下:AA打印1次,BB打印2次,CC打印3次,接着,AA打印1次,BB打印2次,CC打印3次,来4轮

// 资源类
class ShareResource {
    /**
     * 1:A 2:B 3:C
     */
    private int number = 1;

    private final Lock lock = new ReentrantLock();

    /**
     * A 的监视器
     */
    private final Condition condition1 = lock.newCondition();

    /**
     * B 的监视器
     */
    private final Condition condition2 = lock.newCondition();

    /**
     * C 的监视器
     */
    private final Condition condition3 = lock.newCondition();

    public void print1() {
        lock.lock();
        try {
            // 1. 判断
            while (number != 1) {
                condition1.await();
            }
            // 2. 干活
            SmallTool.printTimeAndThread(String.valueOf(number));
            // 修改标志位
            number = 2;
            // 3. 实现精确通知
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void print2() {
        lock.lock();
        try {
            // 1. 判断
            while (number != 2) {
                condition2.await();
            }
            // 2. 干活
            for (int i = 1; i <= 2; i++) {
                SmallTool.printTimeAndThread(String.valueOf(number));
            }
            // 修改标志位
            number = 3;
            // 3. 实现精确通知
            condition3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void print3() {
        lock.lock();
        try {
            // 1. 判断
            while (number != 3) {
                condition3.await();
            }
            // 2. 干活
            for (int i = 1; i <= 3; i++) {
                SmallTool.printTimeAndThread(String.valueOf(number));
            }
            // 修改标志位
            number = 1;
            // 3. 实现精确通知
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
public static void main(String[] args) {
    ShareResource shareResource = new ShareResource();

    new Thread(() -> {
        for (int i = 1; i <= 4; i++) {
            shareResource.print1();
        }
    }, "A").start();

    new Thread(() -> {
        for (int i = 1; i <= 4; i++) {
            shareResource.print2();
        }
    }, "B").start();

    new Thread(() -> {
        for (int i = 1; i <= 4; i++) {
            shareResource.print3();
        }
    }, "C").start();
}
// 结果
1672558974888	|	24	|	A	|	1
1672558974889	|	25	|	B	|	2
1672558974889	|	25	|	B	|	2
1672558974889	|	26	|	C	|	3
1672558974889	|	26	|	C	|	3
1672558974889	|	26	|	C	|	3
1672558974889	|	24	|	A	|	1
1672558974889	|	25	|	B	|	2
1672558974889	|	25	|	B	|	2
1672558974890	|	26	|	C	|	3
1672558974890	|	26	|	C	|	3
1672558974890	|	26	|	C	|	3
1672558974890	|	24	|	A	|	1
1672558974890	|	25	|	B	|	2
1672558974890	|	25	|	B	|	2
1672558974890	|	26	|	C	|	3
1672558974890	|	26	|	C	|	3
1672558974890	|	26	|	C	|	3
1672558974890	|	24	|	A	|	1
1672558974890	|	25	|	B	|	2
1672558974890	|	25	|	B	|	2
1672558974890	|	26	|	C	|	3
1672558974890	|	26	|	C	|	3
1672558974890	|	26	|	C	|	3

更多文章在我的语雀平台:https://www.yuque.com/ambition-bcpii/muziteng

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

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

相关文章

论文的未来走向及创新(1)

论文题目 Zero-Shot Learning across Heterogeneous Overlapping Domains 基准方法 Nave Bayes (Unigram) P(utterance∣domain)P(utterance | domain)P(utterance∣domain) is modeled with Nave Bayes model with features being word unigrams in the utterance. Nave Ba…

centos7修改默认yum源为国内源

centos7修改默认yum源为国内源 文章目录centos7修改默认yum源为国内源操作系统环境信息修改yum源步骤修改后效果yum下载的默认镜像地址速度很慢&#xff0c;一般会更改镜像源为国内的镜像地址&#xff0c;比如163&#xff0c;阿里云等&#xff0c;本文介绍下修改yum源的步骤。操…

【回答问题】ChatGPT上线了!给我推荐20个比较流行的图像分割模型!

给我推荐20个比较流行的图像分割模型 U-Net Mask R-CNN FCN DeepLab PSPNet LinkNet UNet SegNet Tiramisu DenseASPP ICNet ENet DANet DenseSeg Fast-SCNN BiSeNet DUNet MaskLab Dense UNet Attention U-Net给我推荐20个比较流行的图像分割模型源码 好的&#xff0c;下面是…

JMeter自定义函数

JMeter二次开发需求一般集中在2个方向&#xff1a;针对请求类&#xff0c;即需要和服务器进行通信的&#xff0c;我们一般是做java请求的二次开发针对数据处理类型&#xff0c;是不需要和服务器进行通信&#xff0c;是在客户端完成的&#xff0c;一般是做JMeter的自定义函数除了…

【谷粒商城基础篇】商品服务开发:属性分组、平台属性

谷粒商城笔记合集 分布式基础篇分布式高级篇高可用集群篇简介&环境搭建项目简介与分布式概念&#xff08;第一、二章&#xff09;基础环境搭建&#xff08;第三章&#xff09;整合SpringCloud整合SpringCloud、SpringCloud alibaba&#xff08;第四、五章&#xff09;前端知…

若依RuoYi整合短信验证码登录

背景&#xff1a;若依默认使用账号密码进行登录&#xff0c;但是咱们客户需要增加一个短信登录功能&#xff0c;即在不更改原有账号密码登录的基础上&#xff0c;整合短信验证码登录。 一、自定义短信登录 token 验证 仿照 UsernamePasswordAuthenticationToken 类&#xff0c…

使没有sudo权限的普通用户可以使用容器

一、基本思路将普通用户加入docker组二、ubuntu组管理命令1、配置文件&#xff08;1&#xff09;文件&#xff1a;/etc/group&#xff08;2&#xff09;权限&#xff1a;①超级用户可读可写②普通用户只读2、查看组&#xff08;1&#xff09;命令cat /etc/group&#xff08;2&a…

【从零开始学习深度学习】34. Pytorch-RNN项目实战:RNN创作歌词案例--使用周杰伦专辑歌词训练模型并创作歌曲【含数据集与源码】

目录RNN项目实战使用周杰伦专辑歌词训练模型并创作歌曲1.语言模型数据集预处理1.1 读取数据集1.2 建立字符索引1.3 时序数据的2种采样方式1.3.1 随机采样1.3.2 相邻采样小结2. 从零实现循环神经网络并进行训练预测2.1 one-hot向量表示2.2 初始化模型参数2.3 定义模型2.4 定义预…

2023 年更新计划

前言 2023 年&#xff0c;会继续更新这个 CSDN 博客了&#xff1b; 看了一下博客数据&#xff0c;有些惨不忍睹&#xff0c;不过之前的内容质量并不高&#xff0c;从头来过吧&#xff1b; 当初个人娱乐写的 STM32 学习笔记&#xff0c;莫名受欢迎&#xff0c;不出意外的话&am…

Spring之Bean实例化的基本流程

目录 一&#xff1a;概述 二&#xff1a;代码展示 一&#xff1a;概述 Spring容器在进行初始化时&#xff0c; 会将xml配置的<bean>的信息封装成一个BeanDefinition对象&#xff0c; 所有的 BeanDefinition存储到一个名为be…

勇闯掘金小游戏为一款多个小游戏的合集游戏,有五个关卡:找掘金、石头剪刀布、寻找藏宝图、打地鼠、抽奖。基于Vue

游戏简介 勇闯掘金小游戏为一款多个小游戏的合集游戏&#xff0c;共有五个关卡&#xff0c;分别为&#xff1a;找掘金、石头剪刀布、寻找藏宝图、打地鼠、抽奖。每个环节20分&#xff0c;满分100分。 完整代码下载地址&#xff1a;勇闯掘金小游戏 快速体验 https://ihope_to…

Acwing---730.机器人问题

机器人问题1.题目2.基本思想3.代码实现1.题目 机器人正在玩一个古老的基于 DOS 的游戏。 游戏中有 N1 座建筑——从 0 到 N 编号&#xff0c;从左到右排列。 编号为 0 的建筑高度为 0 个单位&#xff0c;编号为 i 的建筑高度为 H(i) 个单位。 起初&#xff0c;机器人在编号…

Mycat2(四)mycat2 分库分表

文章目录一、分库分表原理垂直切分&#xff1a;分库水平切分&#xff1a;分表二、分库分表环境准备示例&#xff1a;开始准备环境三、实现分库分表3.1 分库分表--广播表&#xff08;BROADCAST&#xff09;3.2 分库分表--分片表&#xff08;dbpartition、tbpartition&#xff09…

电脑录屏怎么录ppt?三个ppt录制视频的方法

PPT演示文稿是人们在日常生活和学习中常用的工具&#xff0c;它也被广泛地运用于各个方面。最近有不少朋友问小编ppt录制视频的方法&#xff0c;其实ppt录制视频的方法有很多。如果只需要录制PPT内容&#xff0c;可以用PPT自带的“屏幕录制”来录制视频就可以了&#xff0c;如果…

Day848.Copy-on-Write模式 -Java 性能调优实战

Copy-on-Write模式 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于Copy-on-Write模式的内容。 Java 里 String 这个类在实现 replace() 方法的时候&#xff0c;并没有更改原字符串里面 value[]数组的内容&#xff0c;而是创建了一个新字符串&#xff0c;这种方法在…

C++GUI之wxWidgets(10)-编写应用涉及的类和方法(5)-事件处理(4)

目录自定义事件AddPendingEvent()QueueEvent()PushEventHandler()ProcessEvent()wxCommandEvent与新的事件类型一起使用自定义事件 AddPendingEvent() virtual void wxEvtHandler::AddPendingEvent ( const wxEvent & event ) 发布要稍后处理的事件。 此函数类似于Qu…

逆向-还原代码之eth (Interl 64)

// 源程序 #include <stdio.h> #define HIETH_SYSREG_BASE (0x101e0000) #define REG_RESET 0x01C // 外设控制寄存器(IP软复位控制) #define RESET_SHIFT 12 static void hieth_set_regbit(unsigned long addr, int bit, int shift) { unsigned long …

nginx学习笔记1(小d课堂)

我们进入到官网可以看到有很多个版本的nginx。 我们点击documentation&#xff0c;可以看到官方文档&#xff0c;但是这里的文档暂时还没有中文的&#xff1a; 我们这里后期会在linux上进行安装部署nginx。 而我们的nginx就是我们的反向代理服务器。 我们可以这样来配置。 我们…

栈和队列(内附模拟实现代码)

一&#xff0c;栈1.1 栈的概念栈是一种线性表&#xff08;是一种特殊的线性表&#xff09;&#xff0c;栈只允许在固定一端进行插入和删除元素。插入元素的一端称为栈顶&#xff0c;另一端称为栈底。所以栈中的数据元素满足先进后出&#xff08;First In Last Out&#xff09;的…

【数据篇】31 # 如何对海量数据进行优化性能?

说明 【跟月影学可视化】学习笔记。 渲染动态的地理位置 用随机的小圆点模拟地图的小圆点&#xff0c;实现呼吸灯效果 最简单的做法&#xff1a;先创建圆的几何顶点数据&#xff0c;然后对每个圆设置不同的参数来分别一个一个圆绘制上去。 <!DOCTYPE html> <html …