Java生產(chǎn)者消費者的三種實現(xiàn)方式
Java生產(chǎn)者消費者的實現(xiàn)
Java生產(chǎn)者消費者是最基礎的線程同步問題,java崗面試中還是很容易遇到的,之前沒寫過多線程的代碼,面試中被問到很尬啊,面完回來惡補下。
在網(wǎng)上查到大概有5種生產(chǎn)者消費者的寫法,分別如下。
- 用synchronized對存儲加鎖,然后用object原生的wait() 和 notify()做同步。
- 用concurrent.locks.Lock,然后用condition的await() 和signal()做同步。
- 直接使用concurrent.BlockingQueue。
- 使用PipedInputStream/PipedOutputStream。
- 使用信號量semaphore。
我的理解,生產(chǎn)者消費者模式,其實只要保證在存儲端同一時刻只有一個線程讀或?qū)懢筒粫袉栴},然后再去考慮線程同步。
方法1 2 5都比較類似,都是加鎖來限制同一時刻只能有一個讀或?qū)?。而方? 4其實是在存儲內(nèi)部去保證讀和寫的唯一的,最低層肯定還是通過鎖機制來實現(xiàn)的,java底層代碼都封裝好了而已?! ?/p>
我自己嘗試寫了下前三種,代碼如下:
synchronized版本
import java.util.LinkedList;
import java.util.Queue;
public class ProducerAndConsumer {
private final int MAX_LEN = 10;
private Queue<Integer> queue = new LinkedList<Integer>();
class Producer extends Thread {
@Override
public void run() {
producer();
}
private void producer() {
while(true) {
synchronized (queue) {
while (queue.size() == MAX_LEN) {
queue.notify();
System.out.println("當前隊列滿");
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.add(1);
queue.notify();
System.out.println("生產(chǎn)者生產(chǎn)一條任務,當前隊列長度為" + queue.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class Consumer extends Thread {
@Override
public void run() {
consumer();
}
private void consumer() {
while (true) {
synchronized (queue) {
while (queue.size() == 0) {
queue.notify();
System.out.println("當前隊列為空");
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.poll();
queue.notify();
System.out.println("消費者消費一條任務,當前隊列長度為" + queue.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
ProducerAndConsumer pc = new ProducerAndConsumer();
Producer producer = pc.new Producer();
Consumer consumer = pc.new Consumer();
producer.start();
consumer.start();
}
}lock版實現(xiàn),使用了condition做線程之間的同步
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* version 1 doesn't use synchronized to improve performance
*/
public class ProducerAndConsumer1 {
private final int MAX_LEN = 10;
private Queue<Integer> queue = new LinkedList<Integer>();
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
class Producer extends Thread {
@Override
public void run() {
producer();
}
private void producer() {
while(true) {
lock.lock();
try {
while (queue.size() == MAX_LEN) {
System.out.println("當前隊列滿");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.add(1);
condition.signal();
System.out.println("生產(chǎn)者生產(chǎn)一條任務,當前隊列長度為" + queue.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
lock.unlock();
}
}
}
}
class Consumer extends Thread {
@Override
public void run() {
consumer();
}
private void consumer() {
while (true) {
lock.lock();
try {
while (queue.size() == 0) {
System.out.println("當前隊列為空");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.poll();
condition.signal();
System.out.println("消費者消費一條任務,當前隊列長度為" + queue.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
lock.unlock();
}
}
}
}
public static void main(String[] args) {
ProducerAndConsumer pc = new ProducerAndConsumer();
Producer producer = pc.new Producer();
Consumer consumer = pc.new Consumer();
producer.start();
consumer.start();
}
}BlockingQueue版實現(xiàn)
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class ProducerAndConsumer {
private BlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>(10);
class Producer extends Thread {
@Override
public void run() {
producer();
}
private void producer() {
while(true) {
try {
queue.put(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生產(chǎn)者生產(chǎn)一條任務,當前隊列長度為" + queue.size());
try {
Thread.sleep(new Random().nextInt(1000)+500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer extends Thread {
@Override
public void run() {
consumer();
}
private void consumer() {
while (true) {
try {
queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消費者消費一條任務,當前隊列長度為" + queue.size());
try {
Thread.sleep(new Random().nextInt(1000)+500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ProducerAndConsumer pc = new ProducerAndConsumer();
Producer producer = pc.new Producer();
Consumer consumer = pc.new Consumer();
producer.start();
consumer.start();
}
}總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
SpringBoot實現(xiàn)隱式參數(shù)注入的完整指南
這篇文章主要為大家詳細介紹了SpringBoot實現(xiàn)隱式參數(shù)注入的相關方法,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2025-11-11
Spring Cloud體系實現(xiàn)標簽路由的方法示例
這篇文章主要介紹了Spring Cloud體系實現(xiàn)標簽路由的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05
MyBatis動態(tài)SQL foreach標簽實現(xiàn)批量插入的方法示例
這篇文章主要介紹了MyBatis動態(tài)SQL foreach標簽實現(xiàn)批量插入的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-06-06
java如何根據(jù)HttpServletRequest獲取IP地址
文章介紹了幾種代理服務器轉(zhuǎn)發(fā)服務請求頭的方法,這些請求頭可能包含真實IP地址,但并不是所有的代理都會包括這些請求頭,而且這些IP地址可能被偽造2025-03-03
Java gRPC攔截器簡單實現(xiàn)分布式日志鏈路追蹤器過程詳解
有請求的發(fā)送、處理,當然就會有攔截器的需求,例如在服務端通過攔截器統(tǒng)一進行請求認證等操作,這些就需要攔截器來完成,今天松哥先和小伙伴們來聊一聊gRPC中攔截器的基本用法,后面我再整一篇文章和小伙伴們做一個基于攔截器實現(xiàn)的JWT認證的gRPC2023-03-03

