Executor 接口關係
Callable:類似於Runnable,但是可以有返回值
Future:存儲將來執行的結果。Callable被執行完之後的結果,被封裝到Future裏面。
Future 示例:
/**
* 認識Callable,對Runnable進行了擴展
* 對Callable的調用,可以有返回值
*/
package com.mashibing.juc.c_026_01_ThreadPool;
import java.util.concurrent.*;
public class T03_Callable {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<String> c = new Callable() {
@Override
public String call() throws Exception {
return "Hello Callable";
}
};
ExecutorService service = Executors.newCachedThreadPool();
Future<String> future = service.submit(c); //異步
System.out.println(future.get());//阻塞
service.shutdown();
}
}
FutureTask:更加靈活,是Runnable和Future的結合,既是一個Runnable,又可以存結果
FutureTask示例:
/**
* 認識FutureTask
*/
package com.mashibing.juc.c_026_01_ThreadPool;
import java.util.concurrent.*;
public class T06_00_Future {
public static void main(String[] args) throws InterruptedException, ExecutionException {
FutureTask<Integer> task = new FutureTask<>(() -> {
TimeUnit.MILLISECONDS.sleep(500);
return 1000;
}); //new Callable () { Integer call();}
new Thread(task).start();
System.out.println(task.get()); //阻塞
}
}
CompletableFuture
可以用來管理多個Future的結果,對各種各樣的結果進行組合處理。你可以去查查它的API~
提供了很多非常好用的接口,十分友好!
示例:假設你能夠提供一個服務,這個服務查詢各大電商網站同一類產品的價格並彙總展示,你用CompletableFuture開啓三個線程來完成這個任務
package com.mashibing.juc.c_026_01_ThreadPool;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class T06_01_CompletableFuture {
public static void main(String[] args) throws ExecutionException, InterruptedException {
long start, end;
/*start = System.currentTimeMillis();
priceOfTM();
priceOfTB();
priceOfJD();
end = System.currentTimeMillis();
System.out.println("use serial method call! " + (end - start));*/
start = System.currentTimeMillis();
CompletableFuture<Double> futureTM = CompletableFuture.supplyAsync(() -> priceOfTM());
CompletableFuture<Double> futureTB = CompletableFuture.supplyAsync(() -> priceOfTB());
CompletableFuture<Double> futureJD = CompletableFuture.supplyAsync(() -> priceOfJD());
CompletableFuture.allOf(futureTM, futureTB, futureJD).join(); // 提供對於一堆任務的管理:這三個任務全部完成之後,才能繼續向下運行
// CompletableFuture.anyOf(futureTM, futureTB, futureJD).join(); // 任意一個任務完成,就能繼續向下運行
CompletableFuture.supplyAsync(() -> priceOfTM())
.thenApply(String::valueOf)
.thenApply(str -> "price " + str)
.thenAccept(System.out::println);
end = System.currentTimeMillis();
System.out.println("use completable future! " + (end - start));
try {
System.in.read();//因爲裏面全是異步,所以需要阻塞一下,才能正常的等待它們輸出,不然主線程先結束了。。
} catch (IOException e) {
e.printStackTrace();
}
}
private static double priceOfTM() {
delay();
return 1.00;
}
private static double priceOfTB() {
delay();
return 2.00;
}
private static double priceOfJD() {
delay();
return 3.00;
}
/*private static double priceOfAmazon() {
delay();
throw new RuntimeException("product not exist!");
}*/
private static void delay() {
int time = new Random().nextInt(500);
try {
TimeUnit.MILLISECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("After random %s sleep!\n", time);
}
}
線程池
ThreadPoolExecutor:我們通常所說的線程池
ForkJoinPoll:先將任務分解,最後再彙總
如何自定義一個線程池
阿里《Java開發手冊》建議自定義線程池,所以我們先來看看如何自定義一個線程池。
線程池
維護兩個集合:
- 線程集合
- 任務集合
用的是HashSet
定義一個自定義線程池,最多有7個參數,這個面試經常被使勁問
package com.mashibing.juc.c_026_01_ThreadPool;
import java.io.IOException;
import java.util.concurrent.*;
public class T05_00_HelloThreadPool {
static class Task implements Runnable {
private int i;
public Task(int i) {
this.i = i;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Task " + i);
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return "Task{" +
"i=" + i +
'}';
}
}
public static void main(String[] args) {
ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 4,
60, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(4),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
for (int i = 0; i < 8; i++) {
tpe.execute(new Task(i));
}
System.out.println(tpe.getQueue());
tpe.execute(new Task(100));
System.out.println(tpe.getQueue());
tpe.shutdown();
}
}