Java多線程中的concurrent簡析
主要的組件
java.util.concurrent包含了很多內(nèi)容, 本文將會(huì)挑選其中常用的一些類來進(jìn)行大概的說明:
- Executor
- ExecutorService
- ScheduledExecutorService
- Future
- CountDownLatch
- CyclicBarrier
- Semaphore
- ThreadFactory
Executor
Executor是一個(gè)接口,它定義了一個(gè)execute方法,這個(gè)方法接收一個(gè)Runnable,并在其中調(diào)用Runnable的run方法。
我們看一個(gè)Executor的實(shí)現(xiàn):
public class Invoker implements Executor { @Override public void execute(Runnable r) { r.run(); } }
現(xiàn)在我們可以直接調(diào)用該類中的方法:
public void execute() { Executor executor = new Invoker(); executor.execute( () -> { log.info("{}", Thread.currentThread().toString()); }); }
注意,Executor并不一定要求執(zhí)行的任務(wù)是異步的。
ExecutorService
如果我們真正的需要使用多線程的話,那么就需要用到ExecutorService了。
ExecutorService管理了一個(gè)內(nèi)存的隊(duì)列,并定時(shí)提交可用的線程。
我們首先定義一個(gè)Runnable類:
public class Task implements Runnable { @Override public void run() { // task details } }
我們可以通過Executors來方便的創(chuàng)建ExecutorService:
ExecutorService executor = Executors.newFixedThreadPool(10);
上面創(chuàng)建了一個(gè)ThreadPool, 我們也可以創(chuàng)建單線程的ExecutorService:
ExecutorService executor =Executors.newSingleThreadExecutor();
我們這樣提交task:
public void execute() { executor.submit(new Task()); }
因?yàn)镋xecutorService維持了一個(gè)隊(duì)列,所以它不會(huì)自動(dòng)關(guān)閉, 我們需要調(diào)用executor.shutdown() 或者executor.shutdownNow()來關(guān)閉它。
如果想要判斷ExecutorService中的線程在收到shutdown請求后是否全部執(zhí)行完畢,可以調(diào)用如下的方法:
try { executor.awaitTermination( 5l, TimeUnit.SECONDS ); } catch (InterruptedException e) { e.printStackTrace(); }
ScheduledExecutorService
ScheduledExecutorService和ExecutorService很類似,但是它可以周期性的執(zhí)行任務(wù)。
我們這樣創(chuàng)建ScheduledExecutorService:
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService的schedule方法,可以傳入Runnable也可以傳入Callable:
Future<String> future = executorService.schedule(() -> { // ... return "Hello world"; }, 1, TimeUnit.SECONDS); ScheduledFuture<?> scheduledFuture = executorService.schedule(() -> { // ... }, 1, TimeUnit.SECONDS);
還有兩個(gè)比較相近的方法:
scheduleAtFixedRate( Runnable command, long initialDelay, long period, TimeUnit unit ) scheduleWithFixedDelay( Runnable command, long initialDelay, long delay, TimeUnit unit )
兩者的區(qū)別是前者的period是以任務(wù)開始時(shí)間來計(jì)算的,后者是以任務(wù)結(jié)束時(shí)間來計(jì)算。
Future
Future用來獲取異步執(zhí)行的結(jié)果??梢哉{(diào)用cancel(boolean mayInterruptIfRunning) 方法來取消線程的執(zhí)行。
我們看下怎么得到一個(gè)Future對象:
public void invoke() { ExecutorService executorService = Executors.newFixedThreadPool(10); Future<String> future = executorService.submit(() -> { // ... Thread.sleep(10000l); return "Hello world"; }); }
我們看下怎么獲取Future的結(jié)果:
if (future.isDone() && !future.isCancelled()) { try { str = future.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } }
future還可以接受一個(gè)時(shí)間參數(shù),超過指定的時(shí)間,將會(huì)報(bào)TimeoutException。
try { future.get(10, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { e.printStackTrace(); }
CountDownLatch
CountDownLatch是一個(gè)并發(fā)中很有用的類,CountDownLatch會(huì)初始化一個(gè)counter,通過這個(gè)counter變量,來控制資源的訪問。
我們會(huì)在后面的文章詳細(xì)介紹。
CyclicBarrier
CyclicBarrier和CountDownLatch很類似。CyclicBarrier主要用于多個(gè)線程互相等待的情況,可以通過調(diào)用await() 方法等待,知道達(dá)到要等的數(shù)量。
public class Task implements Runnable { private CyclicBarrier barrier; public Task(CyclicBarrier barrier) { this.barrier = barrier; } @Override public void run() { try { LOG.info(Thread.currentThread().getName() + " is waiting"); barrier.await(); LOG.info(Thread.currentThread().getName() + " is released"); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } } }
public void start() { CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> { // ... LOG.info("All previous tasks are completed"); }); Thread t1 = new Thread(new Task(cyclicBarrier), "T1"); Thread t2 = new Thread(new Task(cyclicBarrier), "T2"); Thread t3 = new Thread(new Task(cyclicBarrier), "T3"); if (!cyclicBarrier.isBroken()) { t1.start(); t2.start(); t3.start(); } }
Semaphore
Semaphore包含了一定數(shù)量的許可證,通過獲取許可證,從而獲得對資源的訪問權(quán)限。通過 tryAcquire()來獲取許可,如果獲取成功,許可證的數(shù)量將會(huì)減少。
一旦線程release()許可,許可的數(shù)量將會(huì)增加。
我們看下怎么使用:
static Semaphore semaphore = new Semaphore(10); public void execute() throws InterruptedException { LOG.info("Available permit : " + semaphore.availablePermits()); LOG.info("Number of threads waiting to acquire: " + semaphore.getQueueLength()); if (semaphore.tryAcquire()) { try { // ... } finally { semaphore.release(); } } }
ThreadFactory
ThreadFactory可以很方便的用來創(chuàng)建線程:
public class ThreadFactoryUsage implements ThreadFactory { private int threadId; private String name; public ThreadFactoryUsage(String name) { threadId = 1; this.name = name; } @Override public Thread newThread(Runnable r) { Thread t = new Thread(r, name + "-Thread_" + threadId); log.info("created new thread with id : " + threadId + " and name : " + t.getName()); threadId++; return t; } }
到此這篇關(guān)于Java多線程中的concurrent簡析的文章就介紹到這了,更多相關(guān)concurrent簡析內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何解決Spring的UnsatisfiedDependencyException異常問題
這篇文章主要介紹了如何解決Spring的UnsatisfiedDependencyException異常問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04解決JAVA項(xiàng)目啟動(dòng)卡住,無任何異常信息的問題
這篇文章主要介紹了解決JAVA項(xiàng)目啟動(dòng)卡住,無任何異常信息的問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03MyBatis將查詢出的兩列數(shù)據(jù)裝配成鍵值對的操作方法
這篇文章主要介紹了MyBatis將查詢出的兩列數(shù)據(jù)裝配成鍵值對的操作代碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08在SpringBoot中實(shí)現(xiàn)一個(gè)訂單號生成系統(tǒng)的示例代碼
在Spring Boot中設(shè)計(jì)一個(gè)訂單號生成系統(tǒng),主要考慮到生成的訂單號需要滿足的幾個(gè)要求:唯一性、可擴(kuò)展性、以及可能的業(yè)務(wù)相關(guān)性,本文給大家介紹了幾種常見的解決方案及相應(yīng)的示例代碼,需要的朋友可以參考下2024-02-02Java源碼解析重寫鎖的設(shè)計(jì)結(jié)構(gòu)和細(xì)節(jié)
這篇文章主要為大家介紹了Java源碼解析重寫鎖的設(shè)計(jì)結(jié)構(gòu)和細(xì)節(jié),這小節(jié)我們以共享鎖作為案列,自定義一個(gè)共享鎖。有需要的朋友可以借鑒參考下2022-03-03面試必問項(xiàng)之Set實(shí)現(xiàn)類:TreeSet
這篇文章主要介紹了Java TreeSet類的簡單理解和使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-07-07Spring-Cloud-Function-Spel?漏洞環(huán)境搭建
這篇文章主要介紹了Spring-Cloud-Function-Spel?漏洞復(fù)現(xiàn)及搭建方法,搭建方法也很簡單,首先需要安裝maven jdk,具體安裝過程跟隨小編一起看看吧2022-03-03Java實(shí)現(xiàn)base64圖片編碼數(shù)據(jù)轉(zhuǎn)換為本地圖片的方法
這篇文章主要介紹了Java實(shí)現(xiàn)base64圖片編碼數(shù)據(jù)轉(zhuǎn)換為本地圖片的方法,涉及java編碼轉(zhuǎn)換及圖片文件生成相關(guān)操作技巧,需要的朋友可以參考下2018-06-06