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();
}
}
}
热门相关:宴先生缠得要命 高人竟在我身边 茅山捉鬼人 高甜预警:我家影后超猛的 仙城之王