最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實現(xiàn)異步轉(zhuǎn)同步的多種方法介紹

 更新時間:2025年09月12日 09:06:17   作者:IT樂手  
這篇文章主要為大家詳細介紹了Java實現(xiàn)異步轉(zhuǎn)同步的多種方法的實現(xià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)文章

  • 詳解Java?中的函數(shù)式接口

    詳解Java?中的函數(shù)式接口

    這篇文章主要為大家介紹了Java中的函數(shù)式接口,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助<BR>
    2021-12-12
  • SpringBoot中ClientAbortException: Broken pipe異常解決及優(yōu)化方案

    SpringBoot中ClientAbortException: Broken pipe異常解決及優(yōu)

    這篇文章主要介紹了如何解決 Spring Boot 中的 ClientAbortException: Broken pipe 異常及優(yōu)化方案,異常發(fā)生在 Spring Boot 項目中,表示客戶端與服務(wù)端的 HTTP 請求連接被中斷,接下來由小編給大家介紹一下出現(xiàn)這個問題的原因,需要的朋友可以參考下
    2024-12-12
  • Java模擬并解決緩存穿透問題

    Java模擬并解決緩存穿透問題

    這篇文章主要介紹了Java模擬并解決緩存穿透問題,本文給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-08-08
  • spring security動態(tài)配置url權(quán)限的2種實現(xiàn)方法

    spring security動態(tài)配置url權(quán)限的2種實現(xiàn)方法

    對于使用spring security來說,存在一種需求,就是動態(tài)去配置url的權(quán)限,即在運行時去配置url對應(yīng)的訪問角色。下面這篇文章主要給大家介紹了關(guān)于spring security動態(tài)配置url權(quán)限的2種實現(xiàn)方法,需要的朋友可以參考下
    2018-06-06
  • 詳解Java Selenium中的鼠標控制操作

    詳解Java Selenium中的鼠標控制操作

    本文主要講解如何用java Selenium 控制鼠標在瀏覽器上的操作方法。主要列舉的代碼示例,大家可以自己上代碼執(zhí)行操作看效果,希望對大家有所幫助
    2023-01-01
  • SpringBoot實現(xiàn)在webapp下直接訪問html,jsp

    SpringBoot實現(xiàn)在webapp下直接訪問html,jsp

    這篇文章主要介紹了SpringBoot實現(xiàn)在webapp下直接訪問html,jsp問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Linux 安裝 Oracle Java 8的步驟詳解

    Linux 安裝 Oracle Java 8的步驟詳解

    在Linux上安裝OracleJava8需下載tar.gz包(需登錄Oracle并接受協(xié)議),上傳至服務(wù)器,解壓后配置環(huán)境變量,驗證版本,并可選設(shè)置默認版本,注意系統(tǒng)架構(gòu)匹配及使用rpm安裝,本文給大家介紹Linux 安裝 Oracle Java 8的步驟詳解,感興趣的朋友一起看看吧
    2025-07-07
  • 解決Java中SimpleDateFormat線程不安全的五種方案

    解決Java中SimpleDateFormat線程不安全的五種方案

    SimpleDateFormat 就是一個典型的線程不安全事例,本文主要介紹了解決Java中SimpleDateFormat線程不安全的五種方案,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • Java利用for循環(huán)輸出空心三角形、空心菱形和空心矩形的代碼

    Java利用for循環(huán)輸出空心三角形、空心菱形和空心矩形的代碼

    今天小編就為大家分享一篇關(guān)于Java利用for循環(huán)輸出空心三角形、空心菱形和空心矩形的代碼,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • java圖的深度優(yōu)先遍歷實現(xiàn)隨機生成迷宮

    java圖的深度優(yōu)先遍歷實現(xiàn)隨機生成迷宮

    這篇文章主要為大家詳細介紹了java圖的深度優(yōu)先遍歷實現(xiàn)隨機生成迷宮,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01

最新評論

北京市| 新巴尔虎左旗| 柳江县| 舞阳县| 合川市| 阳城县| 丹棱县| 华亭县| 孟连| 南汇区| 长春市| 海兴县| 瑞丽市| 桂平市| 永丰县| 邳州市| 屏东市| 拜城县| 温宿县| 登封市| 乡宁县| 海口市| 吉林省| 郁南县| 搜索| 筠连县| 敦化市| 松桃| 常宁市| 黔西| 栖霞市| 正安县| 乡宁县| 上杭县| 防城港市| 丹东市| 中牟县| 大方县| 永登县| 磐安县| 宿松县|