Guava提供了一些豐富的并發(fā)工具,幫助開發(fā)者更好地處理并發(fā)編程中的問題。例如,Guava提供了ListenableFuture、CountDownLatch、CyclicBarrier等工具。這些工具對(duì)Java并發(fā)包(java.util.concurrent)進(jìn)行了擴(kuò)展,使其功能更強(qiáng)大,使用更方便。
具體來說,其中ListenableFuture是Guava對(duì)Java Future的擴(kuò)展,它允許你注冊(cè)回調(diào)函數(shù),當(dāng)Future的計(jì)算結(jié)果可用時(shí),這個(gè)回調(diào)函數(shù)會(huì)被執(zhí)行。CountDownLatch和CyclicBarrier則是用于同步的工具類,它們可以讓一組線程等待彼此,然后再一起執(zhí)行。
Guava提供的并發(fā)工具當(dāng)然不僅僅只有ListenableFuture、CountDownLatch、CyclicBarrier等,還有很多其他的,博主這里算是拋磚引玉吧,把我用過的,我認(rèn)為比較好用的,在這里給大家梳理總結(jié)一下,如果大家用到了其他更好用的,歡迎在評(píng)論區(qū)告訴,一起深入交流。那么本篇文章的主角就是ListenableFuture、CountDownLatch和CyclicBarrier,那么下面先簡(jiǎn)單的盤一下這幾個(gè)類的功能特性:
目前maven中央倉庫的最新版本是32.1.3-jre,本篇文章的所有示例也是基于這個(gè)版本:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>32.1.3-jre</version></dependency>
Guava類庫的ListenableFuture是一個(gè)強(qiáng)大的工具,它擴(kuò)展了Java的Future接口,增加了注冊(cè)回調(diào)函數(shù)的功能。下面是一個(gè)使用Guava的ListenableFuture的示例:
public class ListenableFutureExample { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(executorService); ListenableFuture<String> future = listeningExecutorService.submit(new Callable<String>() { @Override public String call() throws Exception { // 模擬異步任務(wù) Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + ":異步任務(wù)執(zhí)行完畢"); return "異步任務(wù)執(zhí)行成功:success"; } }); Futures.addCallback(future, new FutureCallback<String>() { @Override public void onSuccess(String result) { // 異步任務(wù)執(zhí)行成功后的回調(diào)方法 System.out.println(Thread.currentThread().getName() + ":異步任務(wù)執(zhí)行成功,結(jié)果是:" + result); listeningExecutorService.shutdown();//收到回調(diào)結(jié)果后,建議關(guān)注線程池,否則監(jiān)聽回調(diào)程序會(huì)一直阻塞,不會(huì)結(jié)束; } @Override public void onFailure(Throwable t) { // 異步任務(wù)執(zhí)行失敗后的回調(diào)方法 System.out.println("異步任務(wù)執(zhí)行失敗"); t.printStackTrace(); } }, executorService); System.out.println(Thread.currentThread().getName() + ":主線程繼續(xù)執(zhí)行其他任務(wù)..."); }}
在上面這個(gè)示例中,我們使用了Guava的ListeningExecutorService來創(chuàng)建一個(gè)線程池,并通過submit方法提交了一個(gè)異步任務(wù)。該異步任務(wù)模擬了一個(gè)耗時(shí)操作,等待2秒后返回結(jié)果。然后,我們使用Futures.addCallback方法為L(zhǎng)istenableFuture對(duì)象注冊(cè)了一個(gè)回調(diào)函數(shù)。當(dāng)異步任務(wù)執(zhí)行成功時(shí),會(huì)調(diào)用onSuccess方法,并打印出異步任務(wù)的結(jié)果;當(dāng)異步任務(wù)執(zhí)行失敗時(shí),會(huì)調(diào)用onFailure方法,并打印出異常信息。最后,主線程繼續(xù)執(zhí)行其他任務(wù)。需要注意的是:在這里我關(guān)閉了線程池,否則監(jiān)聽回調(diào)程序會(huì)一直阻塞,不會(huì)結(jié)束;
CountDownLatch
在下面這個(gè)示例中,我們使用了Guava類庫的Uninterruptibles.awaitUninterruptibly()方法來等待CountDownLatch的計(jì)數(shù)器變?yōu)?。這與使用Java標(biāo)準(zhǔn)庫中的latch.await()方法類似,但Guava提供的方法能夠更優(yōu)雅地處理中斷。其余部分與之前的示例相同,創(chuàng)建了多個(gè)工作線程,并使用CountDownLatch來協(xié)調(diào)它們的執(zhí)行。當(dāng)所有工作線程都調(diào)用latch.countDown()方法后,計(jì)數(shù)器將變?yōu)?,然后主線程通過Uninterruptibles.awaitUninterruptibly(latch)等待所有工作線程執(zhí)行完畢,并輸出"All worker threads have finished."。
public class GuavaCountDownLatchExample { public static void main(String[] args) { int numberOfThreads = 3; CountDownLatch latch = new CountDownLatch(numberOfThreads); for (int i = 0; i < numberOfThreads; i++) { new Thread(new Worker(latch), "Thread" + i).start(); } Uninterruptibles.awaitUninterruptibly(latch); // 使用Guava的Uninterruptibles類等待所有工作線程執(zhí)行完畢 System.out.println("All worker threads have finished."); }}class Worker implements Runnable { private final CountDownLatch latch; Worker(CountDownLatch latch) { this.latch = latch; } @Override public void run() { try { System.out.println(Thread.currentThread().getName() + " is working."); Thread.sleep((long) (Math.random() * 1000)); // 模擬工作線程執(zhí)行的任務(wù) System.out.println(Thread.currentThread().getName() + " has finished."); } catch (InterruptedException e) { e.printStackTrace(); } finally { latch.countDown(); // 工作線程完成任務(wù)后,計(jì)數(shù)器減一 } }}
在 Guava 類庫中,沒有直接提供 CyclicBarrier 類。CyclicBarrier 是 Java 標(biāo)準(zhǔn)庫中的一個(gè)類,它可以用于多線程間的同步。這里也簡(jiǎn)單梳理一下他的用法,因?yàn)樵谧龆嗑€程間同步協(xié)調(diào)的相關(guān)業(yè)務(wù)時(shí),CountDownLatch和CyclicBarrier,是兩個(gè)繞不過去的選項(xiàng),這里放在一起也好作個(gè)對(duì)比。
在下面這個(gè)示例中,創(chuàng)建了10個(gè)工作線程,每個(gè)線程都執(zhí)行相同的任務(wù)。這些線程通過CyclicBarrier進(jìn)行同步,確保所有線程都達(dá)到屏障點(diǎn)(即調(diào)用cyclicBarrier.await()方法)后再一起繼續(xù)執(zhí)行。當(dāng)所有線程都調(diào)用cyclicBarrier.await()方法后,屏障會(huì)被打破,所有線程可以繼續(xù)執(zhí)行后續(xù)的任務(wù)。在這個(gè)示例中,后續(xù)的任務(wù)是輸出線程名稱和"is running"的消息。
public class CyclicBarrierExample { public static void main(String[] args) { final int totalThread = 10; CyclicBarrier cyclicBarrier = new CyclicBarrier(totalThread); for (int i = 0; i < totalThread; i++) { new Thread(new Task(cyclicBarrier), "Thread" + i).start(); } }}class Task implements Runnable { private CyclicBarrier cyclicBarrier; public Task(CyclicBarrier cyclicBarrier) { this.cyclicBarrier = cyclicBarrier; } @Override public void run() { System.out.println(Thread.currentThread().getName() + " is ready"); try { cyclicBarrier.await(); //等待其他線程到達(dá)屏障點(diǎn) } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " is running"); }}
希望這篇文章能夠?yàn)槟闾峁┯嘘P(guān) Guava 的 并發(fā)工具類的使用方法,讓你在處理異步任務(wù)時(shí)能夠更加得心應(yīng)手
本文鏈接:http://www.www897cc.com/showinfo-26-70425-0.html掌握Guava的并發(fā)工具:輕松應(yīng)對(duì)復(fù)雜并發(fā)場(chǎng)景
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com