目錄
Future FutureTask CompletionService CompletableFutrue比較
核心知識點
無返回值併發執行順序控制
- CountDownLatch
- CyclicBarrier
有返回值或先後順序控制
- FutureTask
- CompletionService
- CompletableFuture
Future FutureTask CompletionService CompletableFutrue比較
下圖參考自:https://blog.csdn.net/u011726984/article/details/79320004
可回調實現方式
Callable
接口定義:
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
接口實現:
package thread;
import java.util.Random;
import java.util.concurrent.Callable;
/**
*
* @function 功能:線程可回調任務
* @author PJL
* @package thread
* @filename CountTask.java
* @time 2020年4月1日 下午12:50:16
*/
public class CallableTask implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int count=new Random().nextInt(10000);
Thread.sleep(count);
System.out.println("---"+count);
return count;
}
}
Supplier
接口定義:
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
接口實現:
package thread;
import java.util.Random;
import java.util.function.Supplier;
/**
*
* @function 功能:可回調的Supplier順序處理線程任務
* @author PJL
* @package thread
* @filename SupplierTask.java
* @time 2020年4月1日 下午1:06:27
*/
public class SupplierTask implements Supplier<Integer>{
@Override
public Integer get() {
int count=new Random().nextInt(10000);
try {
Thread.sleep(count);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("---"+count);
return count;
}
}
併發工具類
CountDownLatch
CountDownLatch 中文名叫閉鎖,通俗的叫法叫柵欄發令槍。它可以模擬用戶同時到達開始併發執行業務的場景,比如秒殺。
package thread;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
/**
* 同步輔助類CountDownLatch等待組線程執行完畢
* @author admin
* @link {@link https://www.cnblogs.com/liun1994/p/7396026.html}
* @screen 場景:
* <li>分佈式計算進行彙總最終結果</li>
* <li>主線程等待子線程執行完的操作</li>
* <li>等待最終執行如初始化資源完成操作</li>
* <li>等待最終執行如系統資源彙總計算</li>
*/
public class WorkerCountDownLatch {
final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(2);// 兩個工人的協作
Worker worker1 = new Worker("zhang san", 5000, latch);
Worker worker2 = new Worker("li si", 8000, latch);
worker1.start();//線程就緒
worker2.start();//線程就緒
latch.await();// 等待所有工人完成工作
System.out.println("all work done at " + sdf.format(new Date()));
}
static class Worker extends Thread {
String workerName;
int workTime;
CountDownLatch latch;
public Worker(String workerName, int workTime, CountDownLatch latch) {
this.workerName = workerName;
this.workTime = workTime;
this.latch = latch;
}
public void run() {
System.out.println("Worker " + workerName + " do work begin at " + sdf.format(new Date()));
doWork();// 工作了
System.out.println("Worker " + workerName + " do work complete at " + sdf.format(new Date()));
latch.countDown();// 工人完成工作,計數器減一
}
private void doWork() {
try {
Thread.sleep(workTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
測試結果:
Worker zhang san do work begin at 2020-04-01 13:47:45
Worker li si do work begin at 2020-04-01 13:47:45
Worker zhang san do work complete at 2020-04-01 13:47:50
Worker li si do work complete at 2020-04-01 13:47:53
all work done at 2020-04-01 13:47:53
CyclicBarrier
CyclicBarrier內部採用了可重入鎖ReentrantLock和Runnable接口,可以控制多任務循環串行。
package thread;
import java.util.concurrent.CyclicBarrier;
/**
*
* @function 功能:CyclicBarrier允許線程之間互相等待
* @author PJL
* @package thread
* @filename WorkerCyclicBarrier.java
* @time 2020年4月1日 下午1:27:51
*/
public class WorkerCyclicBarrier {
static class TaskThread extends Thread {
CyclicBarrier barrier;
public TaskThread(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
try {
// 循環執行A直到完成
Thread.sleep(1000);
System.out.println(getName() + " 執行任務A");
barrier.await();
System.out.println(getName() + " 執行任務 A完成");
// 循環執行B直到完成
Thread.sleep(2000);
System.out.println(getName() + " 執行任務B");
barrier.await();
System.out.println(getName() + " 執行任務 B完成");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
int threadNum = 5;
CyclicBarrier barrier = new CyclicBarrier(threadNum, new Runnable() {
@Override
public void run() {
// 回調處理
System.out.println(Thread.currentThread().getName() + " 完成最後任務");
}
});
for (int i = 0; i < threadNum; i++) {
new TaskThread(barrier).start();
}
}
}
運行打印結果:
Thread-0 執行任務A
Thread-1 執行任務A
Thread-2 執行任務A
Thread-4 執行任務A
Thread-3 執行任務A
Thread-3 完成最後任務
Thread-3 執行任務 A完成
Thread-2 執行任務 A完成
Thread-0 執行任務 A完成
Thread-4 執行任務 A完成
Thread-1 執行任務 A完成
Thread-0 執行任務B
Thread-4 執行任務B
Thread-3 執行任務B
Thread-2 執行任務B
Thread-1 執行任務B
Thread-1 完成最後任務
Thread-1 執行任務 B完成
Thread-2 執行任務 B完成
Thread-3 執行任務 B完成
Thread-4 執行任務 B完成
Thread-0 執行任務 B完成
FutureTask
FutureTask 實現了RunnableFuture接口
/**
* A cancellable asynchronous computation. This class provides a base
* implementation of {@link Future}, with methods to start and cancel
* a computation, query to see if the computation is complete, and
* retrieve the result of the computation. The result can only be
* retrieved when the computation has completed; the {@code get}
* methods will block if the computation has not yet completed. Once
* the computation has completed, the computation cannot be restarted
* or cancelled (unless the computation is invoked using
* {@link #runAndReset}).
*
* <p>A {@code FutureTask} can be used to wrap a {@link Callable} or
* {@link Runnable} object. Because {@code FutureTask} implements
* {@code Runnable}, a {@code FutureTask} can be submitted to an
* {@link Executor} for execution.
*
* <p>In addition to serving as a standalone class, this class provides
* {@code protected} functionality that may be useful when creating
* customized task classes.
*
* @since 1.5
* @author Doug Lea
* @param <V> The result type returned by this FutureTask's {@code get} methods
*/
public class FutureTask<V> implements RunnableFuture<V> {
而RunnableFutrue接口繼承自Runnable和Future接口
/**
* A {@link Future} that is {@link Runnable}. Successful execution of
* the {@code run} method causes completion of the {@code Future}
* and allows access to its results.
* @see FutureTask
* @see Executor
* @since 1.6
* @author Doug Lea
* @param <V> The result type returned by this Future's {@code get} method
*/
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
FutureTask測試:
package thread;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
/**
*
* @function 功能:FutureTask線程返回值獲取方式
* @author PJL
* @package thread
* @filename WorkerFutureTask.java
* @time 2020年4月1日 下午1:11:41
*/
public class WorkerFutureTask {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newCachedThreadPool();
FutureTask<Integer> task1 = new FutureTask<Integer>(new CallableTask());
FutureTask<Integer> task2 = new FutureTask<Integer>(new CallableTask());
FutureTask<Integer> task3 = new FutureTask<Integer>(new CallableTask());
executor.execute(task1);
executor.execute(task2);
executor.execute(task3);
long start = System.currentTimeMillis();
System.out.println("task1結果=" + task1.get());
System.out.println("task2結果=" + task2.get());
System.out.println("task3結果=" + task3.get());
long end = System.currentTimeMillis();
System.out.println("總共耗時=" + (end - start) + "ms");
}
}
測試結果:
---181
---2594
task1結果=2594
task2結果=181
---2816
task3結果=2816
總共耗時=2817ms
注意:FutureTask的get()方法是阻塞的,不區分完成先後順序,所以最長的時間可能是加起來所有任務耗時的總和。
CompletionService
CompletionService 是通過線程干預的模式對線程完成狀態進行監控,它是JDK併發包的接口,其實現是java.util.concurrent.ExecutorCompletionService,需要結合線程池來使用。
測試示例:
package thread;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
*
* @function 功能:線程完成順序干預先後排序
* @author PJL
* @package thread
* @filename WorkerCompletionService.java
* @time 2020年4月1日 下午1:20:14
*/
public class WorkerCompletionService {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newCachedThreadPool();
CompletionService<Integer> completionService=new ExecutorCompletionService<Integer>(executor);
Future<Integer> task1=completionService.submit(new CallableTask());
Future<Integer> task2=completionService.submit(new CallableTask());
Future<Integer> task3=completionService.submit(new CallableTask());
long start = System.currentTimeMillis();
System.out.println("task1結果=" + task1.get());
System.out.println("task2結果=" + task2.get());
System.out.println("task3結果=" + task3.get());
long end = System.currentTimeMillis();
System.out.println("總共耗時=" + (end - start) + "ms");
}
}
測試結果:
---1539
task1結果=1539
---5169
task2結果=5169
---9412
task3結果=9412
總共耗時=9414ms
CompletableFuture
CompletableFuture 實現了Future和CompletionState接口,可實現線程先後完成排序。
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
測試示例:
package thread;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
*
* @function 功能:多線程任務按照完成先後順序返回
* @author PJL
* @package thread
* @filename WorkerCompletableFuture.java
* @time 2020年4月1日 下午1:04:00
*/
public class WorkerCompletableFuture {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newCachedThreadPool();
CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(new SupplierTask(), executor);
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(new SupplierTask(), executor);
CompletableFuture<Integer> task3 = CompletableFuture.supplyAsync(new SupplierTask(), executor);
long start = System.currentTimeMillis();
System.out.println("task1結果=" + task1.get());
System.out.println("task2結果=" + task2.get());
System.out.println("task3結果=" + task3.get());
long end = System.currentTimeMillis();
System.out.println("總共耗時=" + (end - start) + "ms");
}
}
測試結果:
---609
---782
task1結果=782
task2結果=609
---5614
task3結果=5614
總共耗時=5615ms