《吸血鬼倖存者》武器進化公式一覽
https://blog.csdn.net/qq_34562093/article/details/90209520
1、Future
Future模式是多執行緒設計常用的一種設計模式。Future模式可以理解成:我有一個任務,提交給了Future,Future替我完成這個任務。期間我自己可以去做任何想做的事情。一段時間之後,我就便可以從Future那兒取出結果。
Future提供了三種功能:
判斷任務是否完成
能夠中斷任務
能夠獲取任務執行的結果
向執行緒池中提交任務的submit方法不是阻塞方法,而Future.get方法是一個阻塞方法,當submit提交多個任務時,只有所有任務都完成後,才能使用get按照任務的提交順序得到返回結果,所以一般需要使用future.isDone先判斷任務是否全部執行完成,完成後再使用future.get得到結果。(也可以用get (long timeout, TimeUnit unit)方法可以設定超時時間,防止無限時間的等待)
三段式的程式設計:1.啟動多執行緒任務2.處理其他事3.收集多執行緒任務結果,Future雖然可以實現獲取非同步執行結果的需求,但是它沒有提供通知的機制,要麼使用阻塞,在future.get()的地方等待future返回的結果,這時又變成同步操作;要麼使用isDone()輪詢地判斷Future是否完成,這樣會耗費CPU的資源。
解決方法:CompletionService和CompletableFuture(按照任務完成的先後順序獲取任務的結果)
2、CompletionService是java1.8之前最好用的方法,
能夠實現按照任務完成的先後順序獲取任務的結果。
public class TestCompletionService {
private static final String commandstr01 = "hahah";
private static final String commandstr02 = "hahah";
public static void main(String[] args) throws InterruptedException, ExecutionException {
//1、建立一個執行緒池
ExecutorService executorService = Executors.newCachedThreadPool();
CompletionService<String> completionService = new ExecutorCompletionService<String>(executorService);
completionService.submit(new MyThreadt33(commandstr01));
completionService.submit(new MyThreadt44(commandstr01));
executorService.shutdown();
System.out.println(completionService.take().get());
System.out.println(completionService.take().get());
}
}
class MyThreadt33 implements Callable<String>{
private String commandstr; // 要執行的mingling
public MyThreadt33(String commandstr) {
this.commandstr = commandstr;
}
@Override
public String call() throws Exception {
int sum = 0;
for (int i = 0; i < 100; i++) {
Thread.sleep(200);
sum += i;
System.out.println("Mythread3: "+i);
}
return String.valueOf(sum+300000);
}
}
class MyThreadt44 implements Callable<String>{
private String commandstr; // 要執行的mingling
public MyThreadt44(String commandstr) {
this.commandstr = commandstr;
}
@Override
public String call() throws Exception {
int sum = 0;
for (int i = 0; i < 50; i++) {
Thread.sleep(200);
sum += i;
System.out.println("Mythread4: "+i);
}
return String.valueOf(sum+400000);
}
}
CompletionService方法可以通過completionService.take().get()方法獲取最快完成的執行緒的返回結果(若當前沒有執行緒執行完成則阻塞直到最快的執行緒執行結束),第二次呼叫則返回第二快完成的執行緒的返回結果。
3、CompletableFuture介面
所謂非同步呼叫其實就是實現一個可無需等待被調函式的返回值而讓操作繼續執行的方法。簡單的講就是另啟一個執行緒來完成呼叫中的部分計算,使呼叫繼續執行或返回,而不需要等待計算結果。但呼叫者仍需要取執行緒的計算結果。
JDK1.5新增了Future介面,用於描述一個非同步計算的結果。雖然 Future 以及相關使用方法提供了非同步執行任務的能力,但是對於結果的獲取卻是很不方便,只能通過阻塞或者輪詢的方式得到任務的結果。
JDK1.8後提出了CompletableFuture介面實現了Future和CompletionStage兩個介面,CompletionStage可以看做是一個非同步任務執行過程的抽象(CompletionStage代表非同步計算過程中的某一個階段,一個階段完成以後可能會觸發另外一個階段,一個階段的計算執行可以是一個Function,Consumer或者Runnable。比如:
stage.thenApply(x -> square(x)).thenAccept(x -> System.out.print(x)).thenRun(() -> System.out.println()))
我們可以基於CompletableFuture建立任務和鏈式處理多個任務,並實現按照任務完成的先後順序獲取任務的結果。
(1)建立任務
##使用runAsync方法新建一個執行緒來執行Runnable物件(無返回值);
##使用supplyAysnc方法新建執行緒來執行Supplier<T>物件(有返回值);
##基於執行緒池建立
(2)任務的非同步處理
不論Future.get()方法還是CompletableFuture.get()方法都是阻塞的,為了獲取任務的結果同時不阻塞當前執行緒的執行,我們可以使用CompletionStage提供的方法結合callback來實現任務的非同步處理。
##whenComplete:是執行當前任務的執行緒執行繼續執行 whenComplete 的任務。
##whenCompleteAsync:把 whenCompleteAsync 這個任務繼續提交給執行緒池來進行執行,也就是並行執行。
##thenApply:當一個執行緒依賴另一個執行緒時,可以使用 thenApply 方法來把這兩個執行緒序列化
##thenAccept:thenAccept接收上一階段的輸出作為本階段的輸入,並消費處理,無返回結果。
##thenRun:不關心前一階段的計算結果,因為它不需要輸入引數,進行消費處理,無返回結果。
## thenCombine:會把兩個 CompletionStage 的任務都執行完成後,把兩個任務的結果一塊交給 thenCombine 來處理。
## applyToEither :兩個CompletionStage,誰執行返回的結果快,我就用那個CompletionStage的結果進行下一步的轉化操作。
##acceptEither 方法:兩個CompletionStage,誰執行返回的結果快,我就用那個CompletionStage的結果進行下一步的消耗操作
public class TestCompletableFuture {
private static final String commandstr01 = "hahah";
private static final String commandstr02 = "hahah";
private static final String commandstr03 = "hahah";
private static final String commandstr04 = "hahah";
public static void main(String[] args) throws InterruptedException, ExecutionException{
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture.supplyAsync(new MyThreadt444(commandstr02),executorService).whenComplete((result, e) -> {
//執行執行緒執行完以後的操作。
System.out.println(result + " " + e);
}).exceptionally((e) -> {
//丟擲異常
System.out.println("exception " + e);
return "exception";
});
CompletableFuture.supplyAsync(new MyThreadt333(commandstr02),executorService).whenComplete((result, e) -> {
//執行執行緒執行完以後的操作。
System.out.println(result + " " + e);
}).exceptionally((e) -> {
System.out.println("exception " + e);
return "exception";
});
}
}
class MyThreadt333 implements Supplier<String>{
private String commandstr; // 要執行的mingling
public MyThreadt333(String commandstr) {
this.commandstr = commandstr;
}
@Override
public String get() {
int sum = 0;
for (int i = 0; i < 30; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sum += i;
System.out.println("Mythread333: "+i);
}
return String.valueOf(sum+300000);
}
}
class MyThreadt444 implements Supplier<String>{
private String commandstr; // 要執行的mingling
public MyThreadt444(String commandstr) {
this.commandstr = commandstr;
}
@Override
public String get() {
int sum = 0;
for (int i = 0; i < 40; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sum += i;
System.out.println("Mythread444: "+i);
}
return String.valueOf(sum+400000);
}
}
在CompletableFuture介面中除了使用whenComplete還可以使用handle等方法能實現按照任務完成的先後順序獲取任務的結果。
4、幾種多執行緒併發取結果方式的總結