Java中的SynchronousQueue隊(duì)列詳解
簡介
SynchronousQueue是BlockingQueue的一種,所以SynchronousQueue是線程安全的。
SynchronousQueue和其他的BlockingQueue不同的是SynchronousQueue的capacity是0。
即SynchronousQueue不存儲(chǔ)任何元素。
也就是說SynchronousQueue的每一次insert操作,必須等待其他線性的remove操作。
而每一個(gè)remove操作也必須等待其他線程的insert操作。
這種特性可以讓我們想起了Exchanger。和Exchanger不同的是,使用SynchronousQueue可以在兩個(gè)線程中傳遞同一個(gè)對(duì)象。
一個(gè)線程放對(duì)象,另外一個(gè)線程取對(duì)象。
舉例說明
我們舉一個(gè)多線程中傳遞對(duì)象的例子。
還是舉生產(chǎn)者消費(fèi)者的例子,在生產(chǎn)者中我們創(chuàng)建一個(gè)對(duì)象,在消費(fèi)者中我們?nèi)〕鲞@個(gè)對(duì)象。
先看一下用CountDownLatch該怎么做:
@Test
public void useCountdownLatch() throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(2);
AtomicReference<Object> atomicReference= new AtomicReference<>();
CountDownLatch countDownLatch = new CountDownLatch(1);
Runnable producer = () -> {
Object object=new Object();
atomicReference.set(object);
log.info("produced {}",object);
countDownLatch.countDown();
};
Runnable consumer = () -> {
try {
countDownLatch.await();
Object object = atomicReference.get();
log.info("consumed {}",object);
} catch (InterruptedException ex) {
log.error(ex.getMessage(),ex);
}
};
executor.submit(producer);
executor.submit(consumer);
executor.awaitTermination(50000, TimeUnit.MILLISECONDS);
executor.shutdown();
}
上例中,我們使用AtomicReference來存儲(chǔ)要傳遞的對(duì)象,并且定義了一個(gè)型號(hào)量為1的CountDownLatch。
在producer中,我們存儲(chǔ)對(duì)象,并且countDown。
在consumer中,我們await,然后取出對(duì)象。
輸出結(jié)果:
[pool-1-thread-1] INFO com.flydean.SynchronousQueueUsage - produced java.lang.Object@683d1b4b
[pool-1-thread-2] INFO com.flydean.SynchronousQueueUsage - consumed java.lang.Object@683d1b4b
可以看到傳入和輸出了同一個(gè)對(duì)象。
上面的例子我們也可以用SynchronousQueue來改寫:
@Test
public void useSynchronousQueue() throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(2);
SynchronousQueue<Object> synchronousQueue=new SynchronousQueue<>();
Runnable producer = () -> {
Object object=new Object();
try {
synchronousQueue.put(object);
} catch (InterruptedException ex) {
log.error(ex.getMessage(),ex);
}
log.info("produced {}",object);
};
Runnable consumer = () -> {
try {
Object object = synchronousQueue.take();
log.info("consumed {}",object);
} catch (InterruptedException ex) {
log.error(ex.getMessage(),ex);
}
};
executor.submit(producer);
executor.submit(consumer);
executor.awaitTermination(50000, TimeUnit.MILLISECONDS);
executor.shutdown();
}上面的例子中,如果我們使用synchronousQueue,則可以不用手動(dòng)同步,也不需要額外的存儲(chǔ)。
總結(jié)
如果我們需要在代碼中用到這種線程中傳遞對(duì)象的情況,那么使用synchronousQueue吧。
到此這篇關(guān)于Java中的SynchronousQueue隊(duì)列詳解的文章就介紹到這了,更多相關(guān)SynchronousQueue隊(duì)列內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot環(huán)境下junit單元測(cè)試速度優(yōu)化方式
這篇文章主要介紹了SpringBoot環(huán)境下junit單元測(cè)試速度優(yōu)化方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
SpringBoot配置shiro安全框架的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot配置shiro安全框架的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
面向?qū)ο蠛兔嫦蜻^程的區(qū)別(動(dòng)力節(jié)點(diǎn)java學(xué)院整理)
很多朋友不清楚面向?qū)ο蠛兔嫦蜻^程有什么區(qū)別,接下來小編給大家整理了關(guān)于面向?qū)ο蠛兔嫦蜻^程的區(qū)別講解,感興趣的朋友可以參考下2017-04-04
Java如何導(dǎo)出包含多個(gè)Sheet的Excel文件
這篇文章主要為大家詳細(xì)介紹了Java如何導(dǎo)出包含多個(gè)Sheet的Excel文件,文中一共介紹了兩種實(shí)現(xiàn)方法,有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-07-07
Spring加載XSD文件發(fā)生錯(cuò)誤的解決方法
這篇文章主要介紹了Spring加載XSD文件發(fā)生錯(cuò)誤的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
SpringBoot中@Value注入靜態(tài)變量方式
SpringBoot中靜態(tài)變量無法直接用@Value注入,需通過setter方法,@Value('${}')從屬性文件獲取值,@Value('#{}')用于SpEL表達(dá)式,可注入其他bean屬性,注意bean默認(rèn)名稱為類名首字母小寫2025-08-08

