Java 多线程 —— AQS 原理
生活随笔
收集整理的這篇文章主要介紹了
Java 多线程 —— AQS 原理
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
引言
使用Condition實現生產者-消費者模型,并與wait和notify實現的效果相對比。
wait/notify模擬生產者-消費者
面試題:寫一個固定容量同步容器,擁有put和get方法,以及getCount方法能夠支持2個生產線程以及10個消費者線程的阻塞調用。
在《Effective Java》一書中提到:wait()方法()絕大多數情況下都是和while一起使用的。這是因為,當wait()執行完成后,會立刻釋放當前鎖,如果這時其他線程立刻獲得鎖并對變量進行操作,會出現數據不一致的情況,使用while可以確保數據不會出現不一致的情況。
public class ProducerConsumer1<T> {final private LinkedList<T> lists = new LinkedList<>();final private int MAX = 10;// 最多10個元素private int count = 0;public synchronized void put(T t) {while (lists.size() == this.MAX) {// 想想為什么用while而不是iftry {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}lists.add(t);count++;this.notifyAll();// 通知消費者線程進行消費}public synchronized T get() {T t = null;while (lists.size() == 0) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}t = lists.removeFirst();count--;this.notifyAll();// 通知生產者進行生產return t;}public static void main(String[] args) {ProducerConsumer1<String> c = new ProducerConsumer1<>();// 啟動消費者線程for (int i = 0; i < 10; i++) {new Thread(() -> {for (int j = 0; j < 5; j++) {System.out.println(c.get());}}, "c" + i).start();}try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}for (int i = 0; i < 2; i++) {new Thread(() -> {for (int j = 0; j < 25; j++) {c.put(Thread.currentThread().getName() + " " + j);}}).start();}} }Condition模擬生產者-消費者
使用Lock和Condition來實現類似需求時,可以更加精確的指定哪些線程被喚醒,這比notifyAll()效率更高一些。
將上面的程序代碼進行改寫:
public class ProducerConsumer2<T> {final private LinkedList<T> lists = new LinkedList<>();final private int MAX = 10;private int count = 0;private Lock lock = new ReentrantLock();private Condition producer = lock.newCondition();private Condition consumer = lock.newCondition();public void put(T t) {try {lock.lock();while (lists.size() == MAX) {producer.await();}lists.add(t);++count;consumer.signalAll(); // 通知消費者線程進行消費} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public T get() {T t = null;try {lock.lock();while (lists.size() == 0) {consumer.await();}t = lists.removeFirst();count--;producer.signalAll();// 通知生產者進行生產} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}return t;}public static void main(String[] args) {ProducerConsumer2<String> c = new ProducerConsumer2<>();// 啟動消費者線程for (int i = 0; i < 10; i++) {new Thread(() -> {for (int j = 0; j < 5; j++) {System.out.println(c.get());}}, "c" + i).start();}try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}for (int i = 0; i < 2; i++) {new Thread(() -> {for (int j = 0; j < 25; j++) {c.put(Thread.currentThread().getName()+ " " + j);}}).start();}} }鳴謝
《馬士兵老師高并發編程系列》
總結
以上是生活随笔為你收集整理的Java 多线程 —— AQS 原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 多线程 —— Reentran
- 下一篇: Java 多线程 —— 常用并发容器