生產者和消費者問題 synchronized版-> wait/notify juc版->Lock 面試:單例模式、排序演算法、生產者和消費者、死鎖 生產者和消費者問題 Synchronized版 package org.example.pc; public class A { public stati ...
生產者和消費者問題
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();
}
}
}