Java實現(xiàn)異步轉(zhuǎn)同步的多種方法介紹
相信大家在項目開發(fā)過程中會遇到需要將異步操作轉(zhuǎn)換為同步操作的情況,下面給大家介紹 CompletableFuture 的用法
package future;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class Main {
public static void costTimeOperation(int a, int b, final Callback callback) {
Thread thread = new Thread() {
@Override
public void run() {
super.run();
try {
Thread.sleep(2000);
callback.onComplete(a+b);
} catch (Exception e) {
System.out.println(e);
callback.onError(e);
}
}
};
thread.start();
}
interface Callback {
void onComplete(int result);
void onError(Exception e);
}
public static void main(String[] args) {
CompletableFuture<Integer> future = new CompletableFuture<>();
int a = 1;
int b = 2;
costTimeOperation(a, b, new Callback() {
@Override
public void onComplete(int result) {
future.complete(result);
}
@Override
public void onError(Exception e) {
future.complete(null);
}
});
try {
System.out.printf(Locale.getDefault(), "Waiting for result of %d+%d...%n", a,b);
System.out.println(future.get(5000, TimeUnit.MILLISECONDS));
} catch (Exception e) {
System.out.println(e);
}
}
}
方法補充
Android常見的異步轉(zhuǎn)同步的方式是通過Callback + Handler的方式來完成,常見的例子是在子線程請求網(wǎng)絡(luò),成功后調(diào)用Callback,然后通過Handler發(fā)送消息給主線程,讓子線程更新UI。當然了,實際開發(fā)還有好多方式可以實現(xiàn)這種操作。
這里展示Java中的幾種異步轉(zhuǎn)同步的方式。
注意:這里只講實現(xiàn),不講原理,具體原理請自行Google。
1、CountDownLatch
CountDownLatch是一個同步工具類,它允許一個或多個線程一直等待,直到其他線程的操作執(zhí)行完后再執(zhí)行。
這里有三個子任務(wù)Task1、Task2和Task3,我們想在Task2和Task3都執(zhí)行完了以后,才執(zhí)行Task1。實現(xiàn)如下:
1、先自定義一個Runnable,run方法中會打印當前線程,在線程執(zhí)行完畢后會調(diào)用CountDownLatch#countDown()方法。
/**
* 自定義Runnable
*/
private static class CustomRunnable implements Runnable {
private CountDownLatch countDownLatch;
private String name;
private int delayTime;
public CustomRunnable(CountDownLatch countDownLatch, String name, int delayTime) {
this.countDownLatch = countDownLatch;
this.name = name;
this.delayTime = delayTime;
}
@Override
public void run() {
LogUtils.e(TAG, "開始執(zhí)行" + name);
ThreadUtils.logCurrThreadName(TAG + " " + name);
try {
TimeUnit.SECONDS.sleep(delayTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
LogUtils.e(TAG, name + "執(zhí)行完畢");
if (countDownLatch != null) {
countDownLatch.countDown();
}
}
}①初始化CountDownLatch,這里傳入了2,這是因為Task1等待的任務(wù)有2個,Task2和Task3.
②創(chuàng)建自定義Runnable Task1,線程內(nèi)部調(diào)用CountDownLatch#await()方法開始等待。
③創(chuàng)建線程池,依次提交任務(wù)Task1、Task2、Task3。
public void onBtnJavaCountDownLatchClicked() {
/**
* Task2和Task3都執(zhí)行完了以后,才執(zhí)行Task1
*/
countDownLatch = new CountDownLatch(2);
Runnable Task1 = () -> {
LogUtils.e(TAG, "開始執(zhí)行Task1");
ThreadUtils.logCurrThreadName(TAG + " Task1");
try {
// 注意這里是await方法,不是wait方法,不要問我為什么,難受。
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
LogUtils.e(TAG, "Task1執(zhí)行完畢");
};
// 創(chuàng)建線程池
ExecutorService executors = Executors.newFixedThreadPool(3);
// 執(zhí)行任務(wù)。
executors.submit(Task1);
executors.submit(new CustomRunnable(countDownLatch, "Task2", 3));
executors.submit(new CustomRunnable(countDownLatch, "Task3", 5));
// 任務(wù)完成后關(guān)閉線程池
executors.shutdown();
}輸出結(jié)果:
05-24 11:14:32.632 2018-2052/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 開始執(zhí)行Task1
05-24 11:14:32.633 2018-2052/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity Task1: sub Thread,name --> pool-2-thread-1
05-24 11:14:32.634 2018-2053/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 開始執(zhí)行Task2
05-24 11:14:32.634 2018-2053/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity Task2: sub Thread,name --> pool-2-thread-2
05-24 11:14:32.635 2018-2054/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 開始執(zhí)行Task3
05-24 11:14:32.635 2018-2054/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity Task3: sub Thread,name --> pool-2-thread-3
05-24 11:14:35.635 2018-2053/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: Task2執(zhí)行完畢
05-24 11:14:37.636 2018-2054/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: Task3執(zhí)行完畢
05-24 11:14:37.636 2018-2052/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: Task1執(zhí)行完畢
我們先提交了Task1任務(wù),它先執(zhí)行,當執(zhí)行到CountDownLatch#await()方法時開始等待,等待Task2和Task3都執(zhí)行完畢后,Task1才繼續(xù)執(zhí)行,上述log印證了這點。
大家可以想象,如果這里沒有CountDownLatch,那么Task1、Task2和Task3這三個任務(wù)會各自獨立執(zhí)行,互不影響。
添加了CountDownLatch后,我們做到了讓任務(wù)Task2和Task3都執(zhí)行完以后,再繼續(xù)執(zhí)行Task1的任務(wù),代碼是不是很簡單。
2、CyclicBarrier
CyclicBarrier是一個同步輔助類,它允許一組線程互相等待,直到到達某個公共屏障點 (common barrier point)。
①新建CyclicBarrier,它有兩個參數(shù),第一個參數(shù)表示如果有10個線程到達屏障位置時,就會執(zhí)行第二個Runnable參數(shù)的run方法。
CyclicBarrier cyclicBarrier = new CyclicBarrier(10, () -> {
LogUtils.e(TAG, "所有任務(wù)都執(zhí)行完畢了");
ThreadUtils.logCurrThreadName(TAG + " barrierAction");
});②創(chuàng)建10個任務(wù),每個任務(wù)執(zhí)行完畢后都會調(diào)用CyclicBarrier#await()方法。
③將這10個任務(wù)都放入線程池中去執(zhí)行。
List<Runnable> runnables = new ArrayList<>();
for (int i = 0; i < 10; i++) {
int finalI = i;
Runnable runnable = () -> {
LogUtils.e(TAG, "當前是第" + finalI + "個任務(wù),開始執(zhí)行");
ThreadUtils.logCurrThreadName(TAG + " 子任務(wù)");
try {
TimeUnit.SECONDS.sleep(finalI);
} catch (InterruptedException e) {
e.printStackTrace();
}
LogUtils.e(TAG, "當前是第" + finalI + "個任務(wù),執(zhí)行完畢");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
};
runnables.add(runnable);
}
ExecutorService executorService = Executors.newCachedThreadPool();
for (Runnable r : runnables) {
executorService.submit(r);
}
executorService.shutdown();輸出結(jié)果:
05-24 11:55:04.272 2018-2190/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第2個任務(wù),開始執(zhí)行
05-24 11:55:04.272 2018-2190/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 子任務(wù): sub Thread,name --> pool-3-thread-3
05-24 11:55:04.272 2018-2191/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第3個任務(wù),開始執(zhí)行
05-24 11:55:04.272 2018-2191/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 子任務(wù): sub Thread,name --> pool-3-thread-4
05-24 11:55:04.273 2018-2188/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第0個任務(wù),開始執(zhí)行
05-24 11:55:04.273 2018-2188/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 子任務(wù): sub Thread,name --> pool-3-thread-1
05-24 11:55:04.273 2018-2188/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第0個任務(wù),執(zhí)行完畢
05-24 11:55:04.273 2018-2189/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第1個任務(wù),開始執(zhí)行
05-24 11:55:04.273 2018-2189/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 子任務(wù): sub Thread,name --> pool-3-thread-2
05-24 11:55:04.274 2018-2192/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第4個任務(wù),開始執(zhí)行
05-24 11:55:04.274 2018-2192/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 子任務(wù): sub Thread,name --> pool-3-thread-5
05-24 11:55:04.275 2018-2193/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第5個任務(wù),開始執(zhí)行
05-24 11:55:04.275 2018-2193/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 子任務(wù): sub Thread,name --> pool-3-thread-6
05-24 11:55:04.275 2018-2194/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第6個任務(wù),開始執(zhí)行
05-24 11:55:04.275 2018-2194/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 子任務(wù): sub Thread,name --> pool-3-thread-7
05-24 11:55:04.277 2018-2197/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第9個任務(wù),開始執(zhí)行
05-24 11:55:04.278 2018-2197/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 子任務(wù): sub Thread,name --> pool-3-thread-10
05-24 11:55:04.278 2018-2195/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第7個任務(wù),開始執(zhí)行
05-24 11:55:04.278 2018-2195/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 子任務(wù): sub Thread,name --> pool-3-thread-8
05-24 11:55:04.279 2018-2196/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第8個任務(wù),開始執(zhí)行
05-24 11:55:04.279 2018-2196/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 子任務(wù): sub Thread,name --> pool-3-thread-9
05-24 11:55:05.274 2018-2189/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第1個任務(wù),執(zhí)行完畢
05-24 11:55:06.272 2018-2190/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第2個任務(wù),執(zhí)行完畢
05-24 11:55:07.273 2018-2191/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第3個任務(wù),執(zhí)行完畢
05-24 11:55:08.276 2018-2192/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第4個任務(wù),執(zhí)行完畢
05-24 11:55:09.277 2018-2193/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第5個任務(wù),執(zhí)行完畢
05-24 11:55:10.280 2018-2194/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第6個任務(wù),執(zhí)行完畢
05-24 11:55:11.282 2018-2195/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第7個任務(wù),執(zhí)行完畢
05-24 11:55:12.282 2018-2196/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第8個任務(wù),執(zhí)行完畢
05-24 11:55:13.278 2018-2197/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當前是第9個任務(wù),執(zhí)行完畢
05-24 11:55:13.278 2018-2197/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 所有任務(wù)都執(zhí)行完畢了
05-24 11:55:13.278 2018-2197/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity barrierAction: sub Thread,name --> pool-3-thread-10
從輸出結(jié)果可以看出,當在10個線程中調(diào)用了CyclicBarrier#await()方法后,我們的CyclicBarrier對象初始化時傳入的Runnable對象的run方法會被調(diào)用。
3、FutureTask
這里提供三種實現(xiàn)方式:
①Callable + Future + ExecutorService
第一步,先自定義一個Callable對象,在call方法中進行計算并將結(jié)果返回。
class CustomCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
LogUtils.e(TAG, "在子線程進行計算");
ThreadUtils.logCurrThreadName(TAG + " Task start");
int sum = 0;
for (int i = 0; i < 20; i++) {
Thread.sleep(100);
sum += i;
ThreadUtils.logCurrThreadName(TAG + " Task sum:" + sum);
}
ThreadUtils.logCurrThreadName(TAG + " Task end");
return sum;
}
}第二步,創(chuàng)建線程池,通過submit方法提交剛才的自定義Callable,并通過Future接受返回結(jié)果。
第三步,通過Future#get()方法完成異步轉(zhuǎn)同步操作。
public void onBtnJavaCallableFutureClicked() {
// Callable + Future + ExecutorService
ThreadUtils.logCurrThreadName(TAG + " main start");
ExecutorService executorService = Executors.newCachedThreadPool();
CustomCallable task = new CustomCallable();
Future<Integer> result = executorService.submit(task);
executorService.shutdown();
ThreadUtils.logCurrThreadName(TAG + " main 111");
try {
LogUtils.e(TAG, "task執(zhí)行結(jié)果:" + result.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
ThreadUtils.logCurrThreadName(TAG + " main 222:" + i);
}
ThreadUtils.logCurrThreadName(TAG + " main 主線程任務(wù)執(zhí)行完畢");
}輸出結(jié)果:
05-24 12:06:36.609 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main start: main Thread,name --> main
05-24 12:06:36.613 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 111: main Thread,name --> main
05-24 12:06:36.614 2314-2344/com.tiny.demo.firstlinecode E/FutureTaskActivity: 在子線程進行計算
05-24 12:06:36.614 2314-2344/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task start: sub Thread,name --> pool-2-thread-1
05-24 12:06:36.714 2314-2344/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:0: sub Thread,name --> pool-2-thread-1
05-24 12:06:36.814 2314-2344/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:1: sub Thread,name --> pool-2-thread-1
05-24 12:06:36.915 2314-2344/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:3: sub Thread,name --> pool-2-thread-1
05-24 12:06:37.016 2314-2344/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:6: sub Thread,name --> pool-2-thread-1
05-24 12:06:37.116 2314-2344/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:10: sub Thread,name --> pool-2-thread-1
05-24 12:06:37.217 2314-2344/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:15: sub Thread,name --> pool-2-thread-1
05-24 12:06:37.318 2314-2344/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:21: sub Thread,name --> pool-2-thread-1
05-24 12:06:37.418 2314-2344/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:28: sub Thread,name --> pool-2-thread-1
05-24 12:06:37.519 2314-2344/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:36: sub Thread,name --> pool-2-thread-1
05-24 12:06:37.620 2314-2344/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:45: sub Thread,name --> pool-2-thread-1
05-24 12:06:37.620 2314-2344/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task end: sub Thread,name --> pool-2-thread-1
05-24 12:06:37.622 2314-2314/com.tiny.demo.firstlinecode E/FutureTaskActivity: task執(zhí)行結(jié)果:45
05-24 12:06:37.622 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:0: main Thread,name --> main
05-24 12:06:37.623 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:1: main Thread,name --> main
05-24 12:06:37.623 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:2: main Thread,name --> main
05-24 12:06:37.623 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:3: main Thread,name --> main
05-24 12:06:37.623 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:4: main Thread,name --> main
05-24 12:06:37.623 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:5: main Thread,name --> main
05-24 12:06:37.623 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:6: main Thread,name --> main
05-24 12:06:37.623 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:7: main Thread,name --> main
05-24 12:06:37.623 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:8: main Thread,name --> main
05-24 12:06:37.623 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:9: main Thread,name --> main
05-24 12:06:37.623 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 主線程任務(wù)執(zhí)行完畢: main Thread,name --> main
可以看到,在調(diào)用了Future#get方法后,主線程一直在等待子線程的執(zhí)行結(jié)果,當子線程的計算執(zhí)行完畢后,就繼續(xù)執(zhí)行主線程的代碼。
②Callable + FutureTask + ExecutorService
與上面的demo類似,只不過我們把Future換成FutureTask。
public void onBtnJavaCallableFutureTaskClicked() {
// Callable + FutureTask + ExecutorService
ThreadUtils.logCurrThreadName(TAG + " main start");
ExecutorService executorService = Executors.newCachedThreadPool();
CustomCallable task = new CustomCallable();
FutureTask<Integer> futureTask = new FutureTask<>(task);
executorService.submit(futureTask);
executorService.shutdown();
ThreadUtils.logCurrThreadName(TAG + " main 111");
try {
LogUtils.e(TAG, "task執(zhí)行結(jié)果:" + futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
ThreadUtils.logCurrThreadName(TAG + " main 222:" + i);
}
ThreadUtils.logCurrThreadName(TAG + " main 主線程任務(wù)執(zhí)行完畢");
}輸出結(jié)果:
05-24 12:10:08.028 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main start: main Thread,name --> main
05-24 12:10:08.029 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 111: main Thread,name --> main
05-24 12:10:08.030 2314-2362/com.tiny.demo.firstlinecode E/FutureTaskActivity: 在子線程進行計算
05-24 12:10:08.030 2314-2362/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task start: sub Thread,name --> pool-3-thread-1
05-24 12:10:08.131 2314-2362/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:0: sub Thread,name --> pool-3-thread-1
05-24 12:10:08.232 2314-2362/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:1: sub Thread,name --> pool-3-thread-1
05-24 12:10:08.333 2314-2362/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:3: sub Thread,name --> pool-3-thread-1
05-24 12:10:08.434 2314-2362/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:6: sub Thread,name --> pool-3-thread-1
05-24 12:10:08.534 2314-2362/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:10: sub Thread,name --> pool-3-thread-1
05-24 12:10:08.635 2314-2362/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:15: sub Thread,name --> pool-3-thread-1
05-24 12:10:08.735 2314-2362/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:21: sub Thread,name --> pool-3-thread-1
05-24 12:10:08.836 2314-2362/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:28: sub Thread,name --> pool-3-thread-1
05-24 12:10:08.937 2314-2362/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:36: sub Thread,name --> pool-3-thread-1
05-24 12:10:09.038 2314-2362/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:45: sub Thread,name --> pool-3-thread-1
05-24 12:10:09.038 2314-2362/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task end: sub Thread,name --> pool-3-thread-1
05-24 12:10:09.038 2314-2314/com.tiny.demo.firstlinecode E/FutureTaskActivity: task執(zhí)行結(jié)果:45
05-24 12:10:09.038 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:0: main Thread,name --> main
05-24 12:10:09.038 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:1: main Thread,name --> main
05-24 12:10:09.038 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:2: main Thread,name --> main
05-24 12:10:09.039 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:3: main Thread,name --> main
05-24 12:10:09.039 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:4: main Thread,name --> main
05-24 12:10:09.039 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:5: main Thread,name --> main
05-24 12:10:09.039 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:6: main Thread,name --> main
05-24 12:10:09.039 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:7: main Thread,name --> main
05-24 12:10:09.039 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:8: main Thread,name --> main
05-24 12:10:09.039 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:9: main Thread,name --> main
05-24 12:10:09.039 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 主線程任務(wù)執(zhí)行完畢: main Thread,name --> main
可以看到,輸出結(jié)果跟上個例子一致。
③Callable + FutureTask + Thread
這里我們將上面例子中的線程池換成Thread,其他不變。
public void onViewClicked() {
// Callable + FutureTask + Thread
ThreadUtils.logCurrThreadName(TAG + " main start");
CustomCallable task = new CustomCallable();
FutureTask<Integer> futureTask = new FutureTask<>(task);
Thread thread = new Thread(futureTask);
thread.start();
ThreadUtils.logCurrThreadName(TAG + " main 111");
try {
LogUtils.e(TAG, "task執(zhí)行結(jié)果:" + futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
ThreadUtils.logCurrThreadName(TAG + " main 222:" + i);
}
ThreadUtils.logCurrThreadName(TAG + " main 主線程任務(wù)執(zhí)行完畢");
}輸出結(jié)果:
05-24 12:12:08.493 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main start: main Thread,name --> main
05-24 12:12:08.495 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 111: main Thread,name --> main
05-24 12:12:08.496 2314-2377/com.tiny.demo.firstlinecode E/FutureTaskActivity: 在子線程進行計算
05-24 12:12:08.496 2314-2377/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task start: sub Thread,name --> Thread-215
05-24 12:12:08.596 2314-2377/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:0: sub Thread,name --> Thread-215
05-24 12:12:08.698 2314-2377/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:1: sub Thread,name --> Thread-215
05-24 12:12:08.798 2314-2377/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:3: sub Thread,name --> Thread-215
05-24 12:12:08.899 2314-2377/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:6: sub Thread,name --> Thread-215
05-24 12:12:09.000 2314-2377/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:10: sub Thread,name --> Thread-215
05-24 12:12:09.100 2314-2377/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:15: sub Thread,name --> Thread-215
05-24 12:12:09.202 2314-2377/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:21: sub Thread,name --> Thread-215
05-24 12:12:09.303 2314-2377/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:28: sub Thread,name --> Thread-215
05-24 12:12:09.404 2314-2377/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:36: sub Thread,name --> Thread-215
05-24 12:12:09.506 2314-2377/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task sum:45: sub Thread,name --> Thread-215
05-24 12:12:09.507 2314-2377/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity Task end: sub Thread,name --> Thread-215
05-24 12:12:09.507 2314-2314/com.tiny.demo.firstlinecode E/FutureTaskActivity: task執(zhí)行結(jié)果:45
05-24 12:12:09.507 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:0: main Thread,name --> main
05-24 12:12:09.507 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:1: main Thread,name --> main
05-24 12:12:09.507 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:2: main Thread,name --> main
05-24 12:12:09.507 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:3: main Thread,name --> main
05-24 12:12:09.507 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:4: main Thread,name --> main
05-24 12:12:09.507 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:5: main Thread,name --> main
05-24 12:12:09.507 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:6: main Thread,name --> main
05-24 12:12:09.507 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:7: main Thread,name --> main
05-24 12:12:09.507 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:8: main Thread,name --> main
05-24 12:12:09.507 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 222:9: main Thread,name --> main
05-24 12:12:09.507 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: FutureTaskActivity main 主線程任務(wù)執(zhí)行完畢: main Thread,name --> main
輸出效果與上面一致。
4、rxjava
RxJava在處理異步任務(wù)方面特別強悍,這里通過兩個例子說明。
map——讓異步任務(wù)順序執(zhí)行
首先,我們通過一個例子讓幾個異步任務(wù)依次順序執(zhí)行,下一個任務(wù)的啟動依賴于上一個任務(wù)的結(jié)果。
這里我們舉一個注冊完成后直接登錄的例子。
大體流程如下:
注冊請求 --> 注冊響應(yīng) --> 登錄請求 --> 登錄響應(yīng)
①先創(chuàng)建四個Bean,用于模擬數(shù)據(jù)轉(zhuǎn)換。分別是注冊請求Bean,注冊請求響應(yīng)Bean,登錄請求Bean,登錄請求相應(yīng)Bean。
下面這個是注冊請求Bean的部分代碼,相應(yīng)的getter/setter方法和toString方法已省略。
public class RegisterReqBean {
private String name;
private String phone;
private String pwd;
public RegisterReqBean(String name, String phone, String pwd) {
this.name = name;
this.phone = phone;
this.pwd = pwd;
}
...
}注冊請求相應(yīng)Bean:
public class RegisterRespBean {
private String name;
private String pwd;
private String msg;
...
}登錄請求Bean:
public class LoginReqBean {
private String name;
private String pwd;
private String msg;
...
}登錄請求響應(yīng)Bean:
public class LoginRespBean {
private String name;
private String pwd;
private String msg;
...
}②創(chuàng)建對應(yīng)的Observable對象,準備好數(shù)據(jù)轉(zhuǎn)換的素材。
RegisterReqBean registerReqBean = new RegisterReqBean("貓了個咪", "13333333333", "123456");
Observable registerRequest = Observable.create(new ObservableOnSubscribe<RegisterReqBean>() {
@Override
public void subscribe(ObservableEmitter<RegisterReqBean> emitter) throws Exception {
LogUtils.e(TAG, "注冊請求 registerReqBean:" + registerReqBean);
ThreadUtils.logCurrThreadName(TAG + " 注冊請求成功");
emitter.onNext(registerReqBean);
LogUtils.e(TAG, "發(fā)送注冊請求");
emitter.onComplete();
LogUtils.e(TAG, "發(fā)送注冊請求完成");
}
});
// 模擬注冊響應(yīng)。將RegisterReqBean轉(zhuǎn)化為RegisterRespBean。
Function mockRegisterResp = new Function<RegisterReqBean, RegisterRespBean>() {
@Override
public RegisterRespBean apply(RegisterReqBean registerReqBean) throws Exception {
RegisterRespBean registerRespBean = new RegisterRespBean(registerReqBean.getName(),
registerReqBean.getPwd(), "恭喜您注冊成功");
LogUtils.e(TAG, "注冊響應(yīng) registerRespBean:" + registerRespBean);
TimeUnit.SECONDS.sleep(5);// 模擬網(wǎng)絡(luò)延遲
ThreadUtils.logCurrThreadName(TAG + " 注冊響應(yīng)成功");
return registerRespBean;
}
};
// 模擬登錄請求。將RegisterRespBean轉(zhuǎn)化為LoginReqBean。
Function mockLoginReq = new Function<RegisterRespBean, LoginReqBean>() {
@Override
public LoginReqBean apply(RegisterRespBean registerRespBean) throws Exception {
LoginReqBean loginReqBean = new LoginReqBean(registerRespBean.getName() + " 我要登陸", registerRespBean.getPwd());
LogUtils.e(TAG, "登錄請求 loginReqBean:" + loginReqBean);
ThreadUtils.logCurrThreadName(TAG + " 登錄請求成功");
return loginReqBean;
}
};
// 模擬登錄響應(yīng)。將LoginReqBean轉(zhuǎn)化為LoginRespBean。
Function mockLoginResp = new Function<LoginReqBean, LoginRespBean>() {
@Override
public LoginRespBean apply(LoginReqBean loginReqBean) throws Exception {
LoginRespBean loginRespBean = new LoginRespBean(loginReqBean.getName(),
loginReqBean.getPwd(), "恭喜您登錄成功");
LogUtils.e(TAG, "登錄響應(yīng) loginRespBean:" + loginRespBean);
TimeUnit.SECONDS.sleep(5);// 模擬網(wǎng)絡(luò)延遲
ThreadUtils.logCurrThreadName(TAG + " 登錄響應(yīng)成功");
return loginRespBean;
}
};
// 模擬接受登錄響應(yīng)結(jié)果。
Observer<LoginRespBean> resultObserver = new Observer<LoginRespBean>() {
@Override
public void onSubscribe(Disposable d) {
LogUtils.e(TAG, "onSubscribe");
}
@Override
public void onNext(LoginRespBean loginRespBean) {
LogUtils.e(TAG, "onNext 登錄成功,可以更新UI了。 loginRespBean:" + loginRespBean);
ThreadUtils.logCurrThreadName(TAG + " ");
}
@Override
public void onError(Throwable e) {
LogUtils.e(TAG, "onError e:" + e.getMessage());
}
@Override
public void onComplete() {
LogUtils.e(TAG, "onComplete");
}
};③使用map操作符進行轉(zhuǎn)化
registerRequest.subscribeOn(Schedulers.io())
.observeOn(Schedulers.newThread())
.map(mockRegisterResp)
.observeOn(Schedulers.io())
.map(mockLoginReq)
.observeOn(Schedulers.newThread())
.map(mockLoginResp)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(resultObserver);最后的輸出結(jié)果:
05-24 13:22:17.823 2314-2314/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: onSubscribe
05-24 13:22:17.826 2314-2619/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 注冊請求 registerReqBean:RegisterReqBean{name='貓了個咪', phone='13333333333', pwd='123456'}
05-24 13:22:17.826 2314-2619/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 注冊請求成功: sub Thread,name --> RxCachedThreadScheduler-1
05-24 13:22:17.827 2314-2619/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 發(fā)送注冊請求
05-24 13:22:17.827 2314-2619/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 發(fā)送注冊請求完成
05-24 13:22:17.830 2314-2620/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 注冊響應(yīng) registerRespBean:RegisterRespBean{name='貓了個咪', pwd='123456', msg='恭喜您注冊成功'}
05-24 13:22:22.833 2314-2620/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 注冊響應(yīng)成功: sub Thread,name --> RxNewThreadScheduler-1
05-24 13:22:22.835 2314-2622/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 登錄請求 loginReqBean:LoginReqBean{name='貓了個咪 我要登陸', pwd='123456'}
05-24 13:22:22.835 2314-2622/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 登錄請求成功: sub Thread,name --> RxCachedThreadScheduler-2
05-24 13:22:22.836 2314-2623/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 登錄響應(yīng) loginRespBean:LoginRespBean{name='貓了個咪 我要登陸', pwd='123456', msg='恭喜您登錄成功'}
05-24 13:22:27.838 2314-2623/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 登錄響應(yīng)成功: sub Thread,name --> RxNewThreadScheduler-2
05-24 13:22:27.838 2314-2314/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: onNext 登錄成功,可以更新UI了。 loginRespBean:LoginRespBean{name='貓了個咪 我要登陸', pwd='123456', msg='恭喜您登錄成功'}
05-24 13:22:27.838 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity : main Thread,name --> main
05-24 13:22:27.838 2314-2314/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: onComplete
merge——多個異步任務(wù)執(zhí)行完畢后在執(zhí)行目標任務(wù)
等待多個任務(wù)完成后再執(zhí)行目標任務(wù),不保證順序。
public void onBtnJavaRxjavaMergeClicked() {
/**
* 等待多個任務(wù)完成后再執(zhí)行,不保證順序
*/
Observable o1 = Observable.create((ObservableOnSubscribe<String>) e -> {
ThreadUtils.logCurrThreadName(TAG + " Observable1");
TimeUnit.SECONDS.sleep(5);
e.onNext("第一個Observable");
e.onComplete();
}).subscribeOn(Schedulers.newThread());
Observable o2 = Observable.create((ObservableOnSubscribe<String>) e -> {
ThreadUtils.logCurrThreadName(TAG + " Observable2");
TimeUnit.SECONDS.sleep(3);
e.onNext("第二個Observable");
e.onComplete();
}).subscribeOn(Schedulers.newThread());
Observable o3 = Observable.create((ObservableOnSubscribe<String>) e -> {
ThreadUtils.logCurrThreadName(TAG + " Observable3");
TimeUnit.SECONDS.sleep(1);
e.onNext("第三個Observable");
e.onComplete();
}).subscribeOn(Schedulers.newThread());
/**
* 三個任務(wù)都發(fā)送了onComplete事件后,訂閱者的onComplete方法才會調(diào)用。
*/
Observable.merge(o1, o2, o3)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
LogUtils.e(TAG, "onSubscribe");
}
@Override
public void onNext(Object o) {
LogUtils.e(TAG, "onNext: " + o);
ThreadUtils.logCurrThreadName(TAG + " onNext");
}
@Override
public void onError(Throwable e) {
LogUtils.e(TAG, "onError");
}
@Override
public void onComplete() {
LogUtils.e(TAG, "onComplete");
}
});
}輸出結(jié)果:
05-24 13:26:59.176 2314-2314/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: onSubscribe
05-24 13:26:59.179 2314-2644/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity Observable1: sub Thread,name --> RxNewThreadScheduler-3
05-24 13:26:59.181 2314-2645/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity Observable2: sub Thread,name --> RxNewThreadScheduler-4
05-24 13:26:59.181 2314-2646/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity Observable3: sub Thread,name --> RxNewThreadScheduler-5
05-24 13:27:00.183 2314-2314/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: onNext: 第三個Observable
05-24 13:27:00.183 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity onNext: main Thread,name --> main
05-24 13:27:02.183 2314-2314/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: onNext: 第二個Observable
05-24 13:27:02.184 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity onNext: main Thread,name --> main
05-24 13:27:04.180 2314-2314/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: onNext: 第一個Observable
05-24 13:27:04.181 2314-2314/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity onNext: main Thread,name --> main
05-24 13:27:04.181 2314-2314/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: onComplete
當三個Observable都發(fā)送了onComplete事件后,Observer的onComplete方法才會調(diào)用。
到此這篇關(guān)于Java實現(xiàn)異步轉(zhuǎn)同步的多種方法介紹的文章就介紹到這了,更多相關(guān)Java異步轉(zhuǎn)同步內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mybatis中的mapper.xml使用循環(huán)語句
這篇文章主要介紹了mybatis中的mapper.xml使用循環(huán)語句,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02
Java 用Prometheus搭建實時監(jiān)控系統(tǒng)過程詳解
這篇文章主要介紹了用Prometheus搭建實時監(jiān)控系統(tǒng)過程詳解之上帝之火,普羅米修斯的崛起,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-07-07
解決HttpPost+json請求---服務(wù)器中文亂碼及其他問題
這篇文章主要介紹了解決HttpPost+json請求---服務(wù)器中文亂碼及其他問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01

