Java 多线程 —— AQS 原理
生活随笔
收集整理的這篇文章主要介紹了
Java 多线程 —— AQS 原理
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
引言
使用Condition實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模型,并與wait和notify實(shí)現(xiàn)的效果相對比。
wait/notify模擬生產(chǎn)者-消費(fèi)者
面試題:寫一個固定容量同步容器,擁有put和get方法,以及getCount方法能夠支持2個生產(chǎn)線程以及10個消費(fèi)者線程的阻塞調(diào)用。
在《Effective Java》一書中提到:wait()方法()絕大多數(shù)情況下都是和while一起使用的。這是因?yàn)?#xff0c;當(dāng)wait()執(zhí)行完成后,會立刻釋放當(dāng)前鎖,如果這時其他線程立刻獲得鎖并對變量進(jìn)行操作,會出現(xiàn)數(shù)據(jù)不一致的情況,使用while可以確保數(shù)據(jù)不會出現(xiàn)不一致的情況。
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();// 通知消費(fèi)者線程進(jìn)行消費(fèi)}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();// 通知生產(chǎn)者進(jìn)行生產(chǎn)return t;}public static void main(String[] args) {ProducerConsumer1<String> c = new ProducerConsumer1<>();// 啟動消費(fèi)者線程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模擬生產(chǎn)者-消費(fèi)者
使用Lock和Condition來實(shí)現(xiàn)類似需求時,可以更加精確的指定哪些線程被喚醒,這比notifyAll()效率更高一些。
將上面的程序代碼進(jìn)行改寫:
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(); // 通知消費(fèi)者線程進(jìn)行消費(fèi)} 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();// 通知生產(chǎn)者進(jìn)行生產(chǎn)} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}return t;}public static void main(String[] args) {ProducerConsumer2<String> c = new ProducerConsumer2<>();// 啟動消費(fèi)者線程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();}} }鳴謝
《馬士兵老師高并發(fā)編程系列》
總結(jié)
以上是生活随笔為你收集整理的Java 多线程 —— AQS 原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 多线程 —— Reentran
- 下一篇: apk提取加密素材_从apk包中提取un