java.util.concurrent簡介
java.util.concurrent包提供了很多有用的類蓖扑,方便我們進(jìn)行并發(fā)程序的開發(fā)淋袖。本文將會做一個總體的簡單介紹悼凑。
主要的組件
java.util.concurrent包含了很多內(nèi)容罚屋, 本文將會挑選其中常用的一些類來進(jìn)行大概的說明:
- Executor
- ExecutorService
- ScheduledExecutorService
- Future
- CountDownLatch
- CyclicBarrier
- Semaphore
- ThreadFactory
Executor
Executor是一個接口晦炊,它定義了一個execute方法鞠鲜,這個方法接收一個Runnable宁脊,并在其中調(diào)用Runnable的run方法。
我們看一個Executor的實現(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管理了一個內(nèi)存的隊列,并定時提交可用的線程宋彼。
我們首先定義一個Runnable類:
public class Task implements Runnable {
@Override
public void run() {
// task details
}
}
我們可以通過Executors來方便的創(chuàng)建ExecutorService:
ExecutorService executor = Executors.newFixedThreadPool(10);
上面創(chuàng)建了一個ThreadPool弄砍, 我們也可以創(chuàng)建單線程的ExecutorService:
ExecutorService executor =Executors.newSingleThreadExecutor();
我們這樣提交task:
public void execute() {
executor.submit(new Task());
}
因為ExecutorService維持了一個隊列,所以它不會自動關(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);
還有兩個比較相近的方法:
scheduleAtFixedRate( Runnable command, long initialDelay, long period, TimeUnit unit )
scheduleWithFixedDelay( Runnable command, long initialDelay, long delay, TimeUnit unit )
兩者的區(qū)別是前者的period是以任務(wù)開始時間來計算的檐什,后者是以任務(wù)結(jié)束時間來計算碴卧。
Future
Future用來獲取異步執(zhí)行的結(jié)果∧苏可以調(diào)用cancel(boolean mayInterruptIfRunning) 方法來取消線程的執(zhí)行住册。
我們看下怎么得到一個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還可以接受一個時間參數(shù),超過指定的時間瓮具,將會報TimeoutException荧飞。
try {
future.get(10, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
e.printStackTrace();
}
CountDownLatch
CountDownLatch是一個并發(fā)中很有用的類,CountDownLatch會初始化一個counter名党,通過這個counter變量叹阔,來控制資源的訪問。我們會在后面的文章詳細(xì)介紹传睹。
CyclicBarrier
CyclicBarrier和CountDownLatch很類似耳幢。CyclicBarrier主要用于多個線程互相等待的情況,可以通過調(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ù)量將會減少吱窝。
一旦線程release()許可,許可的數(shù)量將會增加。
我們看下怎么使用:
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;
}
}
愿與諸君共進(jìn)步院峡,大量的面試題及答案還有資深架構(gòu)師錄制的視頻錄像:有Spring兴使,MyBatis,Netty源碼分析照激,高并發(fā)发魄、高性能、分布式俩垃、微服務(wù)架構(gòu)的原理励幼,JVM性能優(yōu)化、分布式架構(gòu)等這些成為架構(gòu)師必備的知識體系口柳,可以微信搜索539413949獲取苹粟,最后祝大家都能拿到自己心儀的offer