synchronized的写法

class PCdemo{
public static void main(String[] args) {
//多个线程操作同一资源
Data data = new Data(); new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thread-1").start(); new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thread-2").start(); new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thread-3").start(); new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thread-4").start();
}
}
//这是一个资源类,
class Data {
private int num = 0;
//加1
public synchronized void increment() throws InterruptedException {
while(num != 0){
this.wait();
}
num++;
System.out.println("当前线程名字:" + Thread.currentThread().getName() + "加1 操作, num为" + num);
this.notifyAll();
}
//减1
public synchronized void decrement() throws InterruptedException {
while(num == 0){
this.wait();
}
num--;
System.out.println("当前线程名字:" + Thread.currentThread().getName() + "减1 操作, num为" + num);
this.notifyAll();
}
}

结果:

这里需要注意一个概念: 虚假唤醒,就是说线程被唤醒了, 但不会被通知 如果把资源类Data中的 increment, decrement方法中的while 换为: if, 那么运行的时候, 二个线程的结果是正常的, 如果二个以上就会出错,结果为

JUC 版本的 生产者和消费者问题

public class JucPCdemo {
public static void main(String[] args) {
//JUC 版本的 就是来替代 synchronized版本的
DataJ data = new DataJ();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thread-1").start(); new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thread-2").start(); new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thread-3").start(); new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thread-4").start();
} } class DataJ{
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition(); private int num = 0;
//加1
public void increment() throws InterruptedException {
//先加锁
lock.lock();
try {
while(num != 0){
condition.await();//这个替代 this.wait()
}
num++;
System.out.println("当前线程名字:" + Thread.currentThread().getName() + "加1 操作, num为" + num);
condition.signalAll();// 这个来替代 this.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
}
//减1
public void decrement() throws InterruptedException {
//先加锁
lock.lock();
try {
while(num == 0){
condition.await();//这个替代 this.wait();
}
num--;
System.out.println("当前线程名字:" + Thread.currentThread().getName() + "减1 操作, num为" + num);
condition.signalAll();// 这个来替代 this.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
}
}

结果同样是正确的

然而 Condition 更强大的是精确通知和精确唤醒, 之前的运行结果线程之间是随机运行的,如果让线程 1,2,3,4 依次循环有序执行, 就要用到Condition

public class JucPCdemo01 {
public static void main(String[] args) {
//JUC 版本的 就是来替代 synchronized版本的
//4个线程依次循环有序执行, num 初始值为0, 线程1--A, 线程2--B, 线程3--C, 线程4--D
DataC data = new DataC();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.printA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thread-1").start(); new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.printB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thread-2").start(); new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.printC();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thread-3").start(); new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.printD();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thread-4").start();
} } class DataC{
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();//对应A
private Condition condition2 = lock.newCondition();//对应B
private Condition condition3 = lock.newCondition();//对应C
private Condition condition4 = lock.newCondition();//对应D private String str = "A";
public void printA() throws InterruptedException {
//先加锁
lock.lock();
try {
while(! "A".equals(str)){
condition1.await();//只要不是 A 就等待
}
System.out.println("当前线程名字:" + Thread.currentThread().getName() + "对应str为" + str);
str = "B";
condition2.signal();//这里指定唤醒 线程2 对应B
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
} public void printB() throws InterruptedException {
//先加锁
lock.lock();
try {
while(!"B".equals(str)){
condition2.await();//只要不是B 就等待
}
System.out.println("当前线程名字:" + Thread.currentThread().getName() + "对应str为" + str);
str = "C";
condition3.signal();//这里指定唤醒 线程3 对应C
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
} public void printC() throws InterruptedException {
//先加锁
lock.lock();
try {
while(! "C".equals(str)){
condition3.await();//只要不是C 就等待
}
System.out.println("当前线程名字:" + Thread.currentThread().getName() + "对应str为" + str);
str = "D";
condition4.signal();//这里指定唤醒 线程4 对应D
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
} public void printD() throws InterruptedException {
//先加锁
lock.lock();
try {
while(! "D".equals(str)){
condition4.await();//只要不是D 就等待
}
System.out.println("当前线程名字:" + Thread.currentThread().getName() + "对应str为" + str);
str = "A";
condition1.signal();//这里指定唤醒 线程1 对应A
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
} }

运行结果为;

JUC 并发编程--02,生产者和消费者 synchronized的写法 , juc的写法. Condition的用法的更多相关文章

  1. Java并发编程(4)--生产者与消费者模式介绍

    一.前言 这种模式在生活是最常见的,那么它的场景是什么样的呢? 下面是我假象的,假设有一个仓库,仓库有一个生产者和一个消费者,消费者过来消费的时候会检测仓库中是否有库存,如果没有了则等待生产,如果有就 ...

  2. JUC 并发编程--01,线程,进程,经典卖票案例, juc的写法

    进程: 就是一个程序, 里面包含多个线程, 比如一个QQ程序 线程: 进程中最小的调度单元, 比如 QQ中的自动保存功能 并发: 多个线程操作同一资源, 抢夺一个cpu的执行片段, 快速交替 并行: ...

  3. 并发编程 02—— ConcurrentHashMap

    Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...

  4. JUC并发编程学习笔记

    JUC并发编程学习笔记 狂神JUC并发编程 总的来说还可以,学到一些新知识,但很多是学过的了,深入的部分不多. 线程与进程 进程:一个程序,程序的集合,比如一个音乐播发器,QQ程序等.一个进程往往包含 ...

  5. JUC并发编程与高性能内存队列disruptor实战-上

    JUC并发实战 Synchonized与Lock 区别 Synchronized是Java的关键字,由JVM层面实现的,Lock是一个接口,有实现类,由JDK实现. Synchronized无法获取锁 ...

  6. 并发编程的锁机制:synchronized和lock

    1. 锁的种类 锁的种类有很多,包括:自旋锁.自旋锁的其他种类.阻塞锁.可重入锁.读写锁.互斥锁.悲观锁.乐观锁.公平锁.可重入锁等等,其余就不列出了.我们重点看如下几种:可重入锁.读写锁.可中断锁. ...

  7. JUC并发编程基石AQS之主流程源码解析

    前言 由于AQS的源码太过凝练,而且有很多分支比如取消排队.等待条件等,如果把所有的分支在一篇文章的写完可能会看懵,所以这篇文章主要是从正常流程先走一遍,重点不在取消排队等分支,之后会专门写一篇取消排 ...

  8. python并发编程02 /多进程、进程的创建、进程PID、join方法、进程对象属性、守护进程

    python并发编程02 /多进程.进程的创建.进程PID.join方法.进程对象属性.守护进程 目录 python并发编程02 /多进程.进程的创建.进程PID.join方法.进程对象属性.守护进程 ...

  9. python 并发编程 多进程 生产者消费者模型介绍

    一 生产者消费者模型介绍 为什么要使用生产者消费者模型 生产者指的是生产数据的任务,消费者指的是处理数据的任务, 生产数据目的,是为了给消费者处理. 在并发编程中,如果生产者处理速度很快,而消费者处理 ...

随机推荐

  1. Win64 驱动内核编程-12.回调监控进线程创建和退出

    回调监控进线程创建和退出 两个注册回调的函数:PsSetCreateProcessNotifyRoutine   进程回调PsSetCreateThreadNotifyRoutine    线程回调分 ...

  2. <JVM中篇:字节码与类的加载篇>04-再谈类的加载器

    笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...

  3. 如何在C艹大作业上用复数计算器拿下一个100分

    0. qt qt简介: 百度百科 下载:官网下载 申请个账号就可以免费用了 安装方式可以在百度上找到,建议安装MinGW,其余自选. 1. 建立第一个qt文件 打开Qt Creator,点击文件,点击 ...

  4. Day004 Scanner对象

    Scanner对象 作用 ​ 我们可以通过Scanner类来获取用户的输入 所属包 ​ java.util.Scanner java 工具类下 基本语法 Scannner s=new Scanner( ...

  5. 【maven】maven创建项目问题

    这个问题困扰了很多,几个月在做大数据课设的时候,本想创建maven项目,但是创建项目失败了.这次又碰到maven创建项目失败,终于解决了.下面按碰到问题的时间来描述,所以需要从头认真看 前提须知 Ma ...

  6. Web端直传数据至OSS

    官方文档 最佳实践 小程序直传实践 支付宝小程序直传实践 微信小程序直传实践 Web端PostObject直传实践 Web端PostObject直传实践简介 JavaScript客户端签名直传 服务端 ...

  7. 2021/5/11 docker的应用

    很快一天过去了,今天虽然没有加班,但是依旧感觉疲惫,弄了一天的docker镜像的问题.作为一名前端开发工程师从以前从未听说过docker到现在懂得了如何运用,也是不容易啊.之前也说过,我们项目结构是前 ...

  8. MSSQL·查询数据库中所有索引的相关信息

    阅文时长 | 0.45分钟 字数统计 | 784字符 主要内容 | 1.引言&背景 2.声明与参考资料 『MSSQL·查询数据库中所有索引的相关信息』 编写人 | SCscHero 编写时间 ...

  9. spring为何要注入接口,而注入接口的实现类就会报错

    首先说明,注入的对象确实为实现类的对象.(并不是实现类的代理对象,注入并不涉及代理) 如果只是单纯注入是可以用实现类接收注入对象的,但是往往开发中会对实现类做增强,如事务,日志等,实现增强的AOP技术 ...

  10. [刷题] 347 Top K Frequent Elements

    要求 给定一个非空数组,返回前k个出现频率最高的元素 示例 [1,1,1,2,2,3], k=2 输出:[1,2] 思路 出队逻辑,普通队列是先进先出,优先队列是按最大/最小值出队 通过堆实现优先队列 ...