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. Metasploit Framework(MSF)的使用

    目录 Metasploit 安装Metasploit 漏洞利用(exploit) 攻击载荷(payload) Meterpreter MS17_010(永恒之蓝) 辅助模块(探测模块) 漏洞利用模块 ...

  2. 如何以最简单的方式安装 KALI 渗透测试框架系统

    0x01 第一步下载 KALI 百度搜索 KALI 官网,找到下载区,我选的是 64 位标准版,但是推荐下载 32 位(功能貌似更全) 这个为下载后的 iso 镜像文件 0x02 第二步打开虚拟机,配 ...

  3. Day009 类和对象的创建

    类和对象的关系 类是一种抽象的数据结构,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物 动物.植物.手机.电脑 Person类.Pet类.Car类等,这些都是用来描述/定义某一类具体的 ...

  4. .NET Design Patterns

    设计模式分组 GoF设计模式著作中的23种设计模式分为3组:创建型(Creational).结构型(Structural)和行为型(Behavional). 创建型 创建型处理对象构造和引用.它们将对 ...

  5. .NET Worker Service 如何优雅退出

    上一篇文章中我们了解了 .NET Worker Service 的入门知识[1],今天我们接着介绍一下如何优雅地关闭和退出 Worker Service. Worker 类 从上一篇文章中,我们已经知 ...

  6. JWT 基本使用

    JWT 基本使用 在上一节中 session 共享功能使用 redis 进行存储,用户量激增时会导致 redis 崩溃,而 JWT 不依赖服务器,能够避免这个问题. 1.传统 session 1.1. ...

  7. CRM应用中可能发生的问题

    CRM系统是公认的提升企业竞争力的强大工具.它既是以客户为中心的思想,又是一种企业管理方案.当然,它还是一种管理软件.在国外,CRM使企业运营得风生水起,但在我国的企业应用中,还是有着很高的失败率和使 ...

  8. opencv——图像直方图与反向投影

    引言 在图像处理中,对于直方图这个概念,肯定不会陌生.但是其原理真的可以信手拈来吗? 本文篇幅有点长,在此列个目录,大家可以跳着看: 分析图像直方图的概念,以及opencv函数calcHist()对于 ...

  9. [设计模式] 设计模式课程(十二)-- 门面模式(Facade)

    概述 也称外观模式 按目的属于结构型模式,按封装属于接口隔离模式 在组件构建过程中,某些接口之间的依赖常常会带来很多问题.甚至根本无法实现.采用添加一层间接(稳定)接口,来隔离本来互相紧密关联的接口 ...

  10. 【转载】kvm迁移

    https://www.jianshu.com/p/60132085a3c9 kvm分静态和动态迁移,静态就是关机迁移,比较简单,动态迁移就是不关闭服务器进行迁移.静态迁移:确定虚拟机关闭 https ...