場景:
生產者(Producer)生產產品,送到中間商(Medium)那里,消費者(Customer)從中間商那里取走產品,中間商只能持有一定數量的產品(如:30),如果中間商那里已經有了30個產品,中間商會通知生產者等一下,店中有空位置放產品時,通知生產者繼續生產,如果中間商那里沒有產品了,會通知消費者等一下,中間商有產品了,通知消費者繼續消費,
Synchronized方法實作生產者消費者問題:
涉及到的執行緒間通信的方法
wait
導致當前執行緒等待,直到另一個執行緒呼叫該物件的notify()方法或notifyAll()方法,當前的執行緒必須擁有該物件的監視器, 該執行緒釋放此監視器的所有權,并等待另一個執行緒通知等待該物件監視器的執行緒通過呼叫notify方法或notifyAll方法notifyAll方法 , 然后執行緒等待,直到它可以重新獲得監視器的所有權并恢復執行,
notify
喚醒正在等待物件監視器的單個執行緒, 如果任何執行緒正在等待這個物件,其中一個被選擇被喚醒, 選擇是任意的,并且由實施的判斷發生, 執行緒通過呼叫wait方法之一等待物件的監視器,呼叫notify后,當前執行緒不會馬上釋放該物件鎖,要等到程式退出同步塊后,當前執行緒才會釋放鎖,
notifyAll
該方法與 notify ()方法的作業方式相同,重要的一點差異是:
notifyAll 使所有原來在該物件上 wait 的執行緒統統退出等待狀態,使得他們全部從等待佇列中移入到同步佇列中去,等待下一次能夠有機會獲取到物件監視器鎖,
代碼
/**
* 中間商
*/
public class Medium {
private int num = 0;
private static final int TOTAL = 30;
/**
* 接收生產資料
*/
public synchronized void put() {
if (num < TOTAL) {
System.out.println(Thread.currentThread() + "增加庫存--------當前庫存" + ++num);
notifyAll();
} else {
System.out.println(Thread.currentThread() + "增加庫存--------庫存已滿" + num);
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 獲取消費者資料
*/
public synchronized void take() {
if (num > 0) {
System.out.println(Thread.currentThread() + "消費庫存--------當前庫存" + --num);
notifyAll();
} else {
System.out.println(Thread.currentThread() + "消費庫存--------庫存不足" + num);
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 生產者
*/
public class Producer implements Runnable{
private Medium medium;
public Producer(Medium medium) {
this.medium = medium;
}
@Override
public void run() {
while (true) {
medium.put();
}
}
}
/**
* 消費者
*/
public class Consumer implements Runnable {
private Medium medium;
public Consumer(Medium medium) {
this.medium = medium;
}
@Override
public void run() {
while (true) {
medium.take();
}
}
}
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 測驗類
*/
public class Main {
public static void main(String[] agrs) {
Medium medium = new Medium();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 3L, TimeUnit.SECONDS,new LinkedBlockingQueue<>(20), new ThreadPoolExecutor.DiscardOldestPolicy());
threadPoolExecutor.prestartAllCoreThreads();
for (int i = 0; i < 5; i++){
threadPoolExecutor.submit(new Producer(medium));
}
for (int i = 0; i < 10; i++){
threadPoolExecutor.submit(new Consumer(medium));
}
}
}
Lock方法實作生產者消費者問題:
涉及到的方法
lock
需要顯示指定起始位置和終止位置,一般使用ReentrantLock類做為鎖,多個執行緒中必須要使用一個,
ReentrantLock
ReentrantLock類做為物件才能保證鎖的生效,且在加鎖和解鎖處需要通過lock()和unlock()顯示指出,所以一般會在finally塊中寫unlock()以防死鎖,
代碼
/**
* 中間商
*/
public class Medium {
private int num = 0;
private static final int TOTAL = 30;
private Lock lock = new ReentrantLock();
private Condition consumerCondition = lock.newCondition();
private Condition producerCondition = lock.newCondition();
/**
* 接收生產資料
*/
public void put() {
lock.lock();
try {
if (num < TOTAL) {
System.out.println(Thread.currentThread() + "增加庫存--------當前庫存" + ++num);
consumerCondition.signalAll();
} else {
System.out.println(Thread.currentThread() + "增加庫存--------庫存已滿" + num);
try {
producerCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
lock.unlock();
}
}
/**
* 獲取消費者資料
*/
public void take() {
lock.lock();
try {
if (num > 0) {
System.out.println(Thread.currentThread() + "消費庫存--------當前庫存" + --num);
producerCondition.signalAll();
} else {
System.out.println(Thread.currentThread() + "消費庫存--------庫存不足" + num);
try {
consumerCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
lock.unlock();
}
}
}
/**
* 生產者
*/
public class Producer implements Runnable{
private Medium medium;
public Producer(Medium medium) {
this.medium = medium;
}
@Override
public void run() {
while (true) {
medium.put();
}
}
}
/**
* 消費者
*/
public class Consumer implements Runnable {
private Medium medium;
public Consumer(Medium medium) {
this.medium = medium;
}
@Override
public void run() {
while (true) {
medium.take();
}
}
}
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 測驗類
*/
public class Main {
public static void main(String[] agrs) {
Medium medium = new Medium();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 3L, TimeUnit.SECONDS,new LinkedBlockingQueue<>(20), new ThreadPoolExecutor.DiscardOldestPolicy());
threadPoolExecutor.prestartAllCoreThreads();
for (int i = 0; i < 5; i++){
threadPoolExecutor.submit(new Producer(medium));
}
for (int i = 0; i < 10; i++){
threadPoolExecutor.submit(new Consumer(medium));
}
}
}
Synchronized和lock用途區別
Synchronized陳述句和ReentrantLock在一般情況下區別不大,但是在非常復雜的同步應用中和需要實作公平鎖功能時,請考慮使用ReentrantLock,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/259459.html
標籤:java
上一篇:Spring IOC詳解
下一篇:IntelliJ Idea解決Could not autowire. No beans of ‘xxxx‘ type found的錯誤提示
