JUC并发编程学习笔记(三)生产者和消费者问题
生产者和消费者问题
synchronized版-> wait/notify
juc版->Lock
面试:单例模式、排序算法、生产者和消费者、死锁
生产者和消费者问题 Synchronized版
package org.example.pc;
public class A {
public static void main(String[] args) {
Date date = new Date();
new Thread(()->{
for (int i = 0; i < 20; i++) {
date.increment();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 20; i++) {
date.decrement();
}
},"B").start();
}
}
//判断等待、业务、通知
class Date{
private int number = 0;
public synchronized void increment(){
if (number!=0){
try {
//不等于0就让该线程等待
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
number++;
// 打印加完后的值
System.out.println(Thread.currentThread().getName()+"=>"+number);
// 通知其他线程,我完成了
this.notify();
}
public synchronized void decrement(){
if (number!=1){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notify();
}
}
存在的问题:A、B、C、D四个线程
在线程中判断业务完成唤醒等待应该使用while循环判断,而非if判断,因为if判断值判断一次,在线程中存在一种状态叫虚假唤醒。
JUC版生产者和消费者问题
代码实现
package org.example.pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//判断等待、业务、通知
public class Date {
private int number = 0;
private Lock lock = new ReentrantLock();
private Condition inCondition = lock.newCondition();
public void increment() {
try {
lock.lock();
while (number != 0) {
inCondition.await();
}
number++;
// 打印加完后的值
System.out.println(Thread.currentThread().getName() + "=>" + number);
// 通知其他线程,我完成了
inCondition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrement() {
try {
lock.lock();
while (number != 1) {
inCondition.await();
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
inCondition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Condition 精准的通知唤醒线程
在传统并发编程中,通过notifily唤醒线程后所有线程都是随机获取到资源的,JUC中可以通过Condition来精准的控制要唤醒哪一个线程资源。任何一个新技术的出现都不会只是为了实现之前已有的效果
代码实现
package org.example.pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class C {
public static void main(String[] args) {
DateC dateC = new DateC();
new Thread(()->{
for (int i = 0; i < 10; i++) dateC.plantA();
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) dateC.plantB();
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) dateC.plantC();
},"C").start();
}
}
class DateC {
private int number = 1;
private Lock lock = new ReentrantLock();
private Condition inCondition1 = lock.newCondition();
private Condition inCondition2 = lock.newCondition();
private Condition inCondition3 = lock.newCondition();
public void plantA(){
try {
lock.lock();
while (number!=1){
inCondition1.await();
}
System.out.println(Thread.currentThread().getName());
number=2;
inCondition2.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void plantB(){
try {
lock.lock();
while (number!=2){
inCondition2.await();
}
System.out.println(Thread.currentThread().getName());
number=3;
inCondition3.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void plantC(){
try {
lock.lock();
while (number!=3){
inCondition3.await();
}
System.out.println(Thread.currentThread().getName());
number=1;
inCondition1.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
JUC并发编程学习笔记(三)生产者和消费者问题的更多相关文章
- JUC并发编程学习笔记
JUC并发编程学习笔记 狂神JUC并发编程 总的来说还可以,学到一些新知识,但很多是学过的了,深入的部分不多. 线程与进程 进程:一个程序,程序的集合,比如一个音乐播发器,QQ程序等.一个进程往往包含 ...
- Java并发编程学习笔记
Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...
- 并发编程学习笔记(15)----Executor框架的使用
Executor执行已提交的 Runnable 任务的对象.此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节.调度等)分离开来的方法.通常使用 Executor 而不是显式地创建 ...
- 并发编程学习笔记(14)----ThreadPoolExecutor(线程池)的使用及原理
1. 概述 1.1 什么是线程池 与jdbc连接池类似,在创建线程池或销毁线程时,会消耗大量的系统资源,因此在java中提出了线程池的概念,预先创建好固定数量的线程,当有任务需要线程去执行时,不用再去 ...
- 并发编程学习笔记(13)----ConcurrentLinkedQueue(非阻塞队列)和BlockingQueue(阻塞队列)原理
· 在并发编程中,我们有时候会需要使用到线程安全的队列,而在Java中如果我们需要实现队列可以有两种方式,一种是阻塞式队列.另一种是非阻塞式的队列,阻塞式队列采用锁来实现,而非阻塞式队列则是采用cas ...
- 并发编程学习笔记(10)----并发工具类CyclicBarrier、Semaphore和Exchanger类的使用和原理
在jdk中,为并发编程提供了CyclicBarrier(栅栏),CountDownLatch(闭锁),Semaphore(信号量),Exchanger(数据交换)等工具类,我们在前面的学习中已经学习并 ...
- 并发编程学习笔记(8)----ThreadLocal的使用及源码分析
1. ThreadLocal的理解 ThreadLocal,顾名思义,就是线程的本地变量,ThreadLocal会为每个线程创建一个本地变量副本,使得使用ThreadLocal管理的变量在多线程的环境 ...
- 并发编程学习笔记(6)----公平锁和ReentrantReadWriteLock使用及原理
(一)公平锁 1.什么是公平锁? 公平锁指的是在某个线程释放锁之后,等待的线程获取锁的策略是以请求获取锁的时间为标准的,即使先请求获取锁的线程先拿到锁. 2.在java中的实现? 在java的并发包中 ...
- 并发编程学习笔记(5)----AbstractQueuedSynchronizer(AQS)原理及使用
(一)什么是AQS? 阅读java文档可以知道,AbstractQueuedSynchronizer是实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量.事件,等等)提供一个框架, ...
- 并发编程学习笔记(4)----jdk5中提供的原子类及Lock使用及原理
(1)jdk中原子类的使用: jdk5中提供了很多原子类,它会使变量的操作变成原子性的. 原子性:原子性指的是一个操作是不可中断的,即使是在多个线程一起操作的情况下,一个操作一旦开始,就不会被其他线程 ...
随机推荐
- Redis的设计与实现(3)-字典
Redis 的数据库使用字典实现, 对数据库的增, 删, 查, 改也是构建在对字典的操作之上的. 字典是哈希键的底层实现之一: 当一个哈希键包含的键值对比较多, 又或者键值对中的元素都是比较长的字符串 ...
- vue基本操作[2] 续更----让世界感知你的存在
Vue文件解析 什么是<template/>标签 template是html5新元素,主要用于保存客户端中的内容,表现为浏览器解析该内容但不渲染出来,可以将一个模板视为正在被存储以供随后在 ...
- Linux 日志服务管理
日志管理 1 系统日志管理 1 rsyslog系统日志服务 日志记录的内容包括: 历史事件:时间,地点,人物,事件 Jul 18 14:30:53 # 时间 ubuntu2204 # 地点 (在哪个主 ...
- boinc使用笔记
安装 yum install -y epel-release yum install -y boinc-client boinc-manager 启动 在图形界面开启终端 boinc boincmgr
- Mysql高级2-SQL性能分析
一.SQL执行频率 MySQL客户端 连接成功后,通过show [session | global] status 命令可以提供服务器状态信息,通过如下指令,可以查看当前数据库的insert,upda ...
- 用Claude-2-100K复刻了胡锡进老师的写作风格
大家好,我是老章 最近玩心大发,用Claude-2-100K复刻了胡锡进老师的写作风格,然后用这个风格点评世间万物. 蛮有意思的,直接看效果吧: 怎么实现的呢?老章不喜欢废话,极简介绍一下步骤. 第一 ...
- Pandas: 将dataframe转换为dict
背景 将Dataframe的每一列数据转换成字典并保存.也就是字段名变为key, 数值变为value. 方案 以下是效果图 参考链接 https://blog.csdn.net/hanyunkaka/ ...
- 4.2 C++ Boost 内存池管理库
Boost 库是一个由C/C++语言的开发者创建并更新维护的开源类库,其提供了许多功能强大的程序库和工具,用于开发高质量.可移植.高效的C应用程序.Boost库可以作为标准C库的后备,通常被称为准标准 ...
- 网络请求-Android篇(Okhttp和Retrofit)
一.OkHttp的介绍和基本用法 OkHttp是一个流行的开源Java和Android应用程序的HTTP客户端.它由Square Inc.开发,提供了一种简单高效的方式来进行应用程序中的HTTP请求. ...
- 《最新出炉》系列初窥篇-Python+Playwright自动化测试-14-playwright操作iframe-番外篇
1.简介 通过前边三篇的学习,想必大家已经对iframe有了一定的认识和了解,今天这一篇主要是对iframe的一些特殊情况的介绍和讲解,主要从iframe的定位.监听事件和执行js脚本三个方面进行展开 ...