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

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

 更新時(shí)間:2025年09月12日 09:06:17   作者:IT樂手  
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)異步轉(zhuǎn)同步的多種方法的實(shí)現(xiàn)與對(duì)比,文中的示例代碼簡(jiǎn)潔易懂,具有一定的借鑒價(jià)值,有需要的小伙伴可以了解下

相信大家在項(xiàng)目開發(fā)過程中會(huì)遇到需要將異步操作轉(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);
        }
    }
}

方法補(bǔ)充

Android常見的異步轉(zhuǎn)同步的方式是通過Callback + Handler的方式來完成,常見的例子是在子線程請(qǐng)求網(wǎng)絡(luò),成功后調(diào)用Callback,然后通過Handler發(fā)送消息給主線程,讓子線程更新UI。當(dāng)然了,實(shí)際開發(fā)還有好多方式可以實(shí)現(xiàn)這種操作。

這里展示Java中的幾種異步轉(zhuǎn)同步的方式。

注意:這里只講實(shí)現(xiàn),不講原理,具體原理請(qǐng)自行Google。

1、CountDownLatch

CountDownLatch是一個(gè)同步工具類,它允許一個(gè)或多個(gè)線程一直等待,直到其他線程的操作執(zhí)行完后再執(zhí)行。

這里有三個(gè)子任務(wù)Task1、Task2和Task3,我們想在Task2和Task3都執(zhí)行完了以后,才執(zhí)行Task1。實(shí)現(xiàn)如下:

1、先自定義一個(gè)Runnable,run方法中會(huì)打印當(dāng)前線程,在線程執(zhí)行完畢后會(huì)調(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,這是因?yàn)門ask1等待的任務(wù)有2個(gè),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í)行,當(dāng)執(zhí)行到CountDownLatch#await()方法時(shí)開始等待,等待Task2和Task3都執(zhí)行完畢后,Task1才繼續(xù)執(zhí)行,上述log印證了這點(diǎn)。

大家可以想象,如果這里沒有CountDownLatch,那么Task1、Task2和Task3這三個(gè)任務(wù)會(huì)各自獨(dú)立執(zhí)行,互不影響。

添加了CountDownLatch后,我們做到了讓任務(wù)Task2和Task3都執(zhí)行完以后,再繼續(xù)執(zhí)行Task1的任務(wù),代碼是不是很簡(jiǎn)單。

2、CyclicBarrier

CyclicBarrier是一個(gè)同步輔助類,它允許一組線程互相等待,直到到達(dá)某個(gè)公共屏障點(diǎn) (common barrier point)。

①新建CyclicBarrier,它有兩個(gè)參數(shù),第一個(gè)參數(shù)表示如果有10個(gè)線程到達(dá)屏障位置時(shí),就會(huì)執(zhí)行第二個(gè)Runnable參數(shù)的run方法。

        CyclicBarrier cyclicBarrier = new CyclicBarrier(10, () -> {
            LogUtils.e(TAG, "所有任務(wù)都執(zhí)行完畢了");
            ThreadUtils.logCurrThreadName(TAG + " barrierAction");
        });

②創(chuàng)建10個(gè)任務(wù),每個(gè)任務(wù)執(zhí)行完畢后都會(huì)調(diào)用CyclicBarrier#await()方法。

③將這10個(gè)任務(wù)都放入線程池中去執(zhí)行。

        List<Runnable> runnables = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            Runnable runnable = () -> {
                LogUtils.e(TAG, "當(dāng)前是第" + finalI + "個(gè)任務(wù),開始執(zhí)行");
                ThreadUtils.logCurrThreadName(TAG + " 子任務(wù)");
                try {
                    TimeUnit.SECONDS.sleep(finalI);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                LogUtils.e(TAG, "當(dāng)前是第" + finalI + "個(gè)任務(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: 當(dāng)前是第2個(gè)任務(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: 當(dāng)前是第3個(gè)任務(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: 當(dāng)前是第0個(gè)任務(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: 當(dāng)前是第0個(gè)任務(wù),執(zhí)行完畢
05-24 11:55:04.273 2018-2189/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當(dāng)前是第1個(gè)任務(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: 當(dāng)前是第4個(gè)任務(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: 當(dāng)前是第5個(gè)任務(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: 當(dāng)前是第6個(gè)任務(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: 當(dāng)前是第9個(gè)任務(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: 當(dāng)前是第7個(gè)任務(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: 當(dāng)前是第8個(gè)任務(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: 當(dāng)前是第1個(gè)任務(wù),執(zhí)行完畢
05-24 11:55:06.272 2018-2190/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當(dāng)前是第2個(gè)任務(wù),執(zhí)行完畢
05-24 11:55:07.273 2018-2191/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當(dāng)前是第3個(gè)任務(wù),執(zhí)行完畢
05-24 11:55:08.276 2018-2192/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當(dāng)前是第4個(gè)任務(wù),執(zhí)行完畢
05-24 11:55:09.277 2018-2193/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當(dāng)前是第5個(gè)任務(wù),執(zhí)行完畢
05-24 11:55:10.280 2018-2194/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當(dāng)前是第6個(gè)任務(wù),執(zhí)行完畢
05-24 11:55:11.282 2018-2195/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當(dāng)前是第7個(gè)任務(wù),執(zhí)行完畢
05-24 11:55:12.282 2018-2196/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當(dāng)前是第8個(gè)任務(wù),執(zhí)行完畢
05-24 11:55:13.278 2018-2197/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 當(dāng)前是第9個(gè)任務(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é)果可以看出,當(dāng)在10個(gè)線程中調(diào)用了CyclicBarrier#await()方法后,我們的CyclicBarrier對(duì)象初始化時(shí)傳入的Runnable對(duì)象的run方法會(huì)被調(diào)用。

3、FutureTask

這里提供三種實(shí)現(xiàn)方式:

①Callable + Future + ExecutorService

第一步,先自定義一個(gè)Callable對(duì)象,在call方法中進(jìn)行計(jì)算并將結(jié)果返回。

    class CustomCallable implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            LogUtils.e(TAG, "在子線程進(jìn)行計(jì)算");
            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: 在子線程進(jìn)行計(jì)算
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é)果,當(dāng)子線程的計(jì)算執(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: 在子線程進(jìn)行計(jì)算
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é)果跟上個(gè)例子一致。

③Callable + FutureTask + Thread

這里我們將上面例子中的線程池?fù)Q成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: 在子線程進(jìn)行計(jì)算
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ù)方面特別強(qiáng)悍,這里通過兩個(gè)例子說明。

map——讓異步任務(wù)順序執(zhí)行

首先,我們通過一個(gè)例子讓幾個(gè)異步任務(wù)依次順序執(zhí)行,下一個(gè)任務(wù)的啟動(dòng)依賴于上一個(gè)任務(wù)的結(jié)果。

這里我們舉一個(gè)注冊(cè)完成后直接登錄的例子。

大體流程如下:

注冊(cè)請(qǐng)求 --> 注冊(cè)響應(yīng) --> 登錄請(qǐng)求 --> 登錄響應(yīng)

①先創(chuàng)建四個(gè)Bean,用于模擬數(shù)據(jù)轉(zhuǎn)換。分別是注冊(cè)請(qǐng)求Bean,注冊(cè)請(qǐng)求響應(yīng)Bean,登錄請(qǐng)求Bean,登錄請(qǐng)求相應(yīng)Bean。

下面這個(gè)是注冊(cè)請(qǐng)求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;
    }
    ...
}

注冊(cè)請(qǐng)求相應(yīng)Bean:

public class RegisterRespBean {
    private String name;
    private String pwd;
    private String msg;
    ...
}

登錄請(qǐng)求Bean:

public class LoginReqBean {
    private String name;
    private String pwd;
    private String msg;
    ...
}

登錄請(qǐng)求響應(yīng)Bean:

public class LoginRespBean {
    private String name;
    private String pwd;
    private String msg;
    ...
}

②創(chuàng)建對(duì)應(yīng)的Observable對(duì)象,準(zhǔn)備好數(shù)據(jù)轉(zhuǎn)換的素材。

        RegisterReqBean registerReqBean = new RegisterReqBean("貓了個(gè)咪", "13333333333", "123456");
        Observable registerRequest = Observable.create(new ObservableOnSubscribe<RegisterReqBean>() {
            @Override
            public void subscribe(ObservableEmitter<RegisterReqBean> emitter) throws Exception {
                LogUtils.e(TAG, "注冊(cè)請(qǐng)求 registerReqBean:" + registerReqBean);
                ThreadUtils.logCurrThreadName(TAG + " 注冊(cè)請(qǐng)求成功");
                emitter.onNext(registerReqBean);
                LogUtils.e(TAG, "發(fā)送注冊(cè)請(qǐng)求");
                emitter.onComplete();
                LogUtils.e(TAG, "發(fā)送注冊(cè)請(qǐng)求完成");
            }
        });

        // 模擬注冊(cè)響應(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(), "恭喜您注冊(cè)成功");
                LogUtils.e(TAG, "注冊(cè)響應(yīng) registerRespBean:" + registerRespBean);
                TimeUnit.SECONDS.sleep(5);// 模擬網(wǎng)絡(luò)延遲
                ThreadUtils.logCurrThreadName(TAG + " 注冊(cè)響應(yīng)成功");
                return registerRespBean;
            }
        };

        // 模擬登錄請(qǐng)求。將RegisterRespBean轉(zhuǎn)化為L(zhǎng)oginReqBean。
        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, "登錄請(qǐng)求 loginReqBean:" + loginReqBean);
                ThreadUtils.logCurrThreadName(TAG + " 登錄請(qǐng)求成功");
                return loginReqBean;
            }
        };

        // 模擬登錄響應(yīng)。將LoginReqBean轉(zhuǎn)化為L(zhǎng)oginRespBean。
        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操作符進(jìn)行轉(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: 注冊(cè)請(qǐng)求 registerReqBean:RegisterReqBean{name='貓了個(gè)咪', phone='13333333333', pwd='123456'}
05-24 13:22:17.826 2314-2619/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 注冊(cè)請(qǐng)求成功: sub Thread,name --> RxCachedThreadScheduler-1
05-24 13:22:17.827 2314-2619/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 發(fā)送注冊(cè)請(qǐng)求
05-24 13:22:17.827 2314-2619/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 發(fā)送注冊(cè)請(qǐng)求完成
05-24 13:22:17.830 2314-2620/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 注冊(cè)響應(yīng) registerRespBean:RegisterRespBean{name='貓了個(gè)咪', pwd='123456', msg='恭喜您注冊(cè)成功'}
05-24 13:22:22.833 2314-2620/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 注冊(cè)響應(yīng)成功: sub Thread,name --> RxNewThreadScheduler-1
05-24 13:22:22.835 2314-2622/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 登錄請(qǐng)求 loginReqBean:LoginReqBean{name='貓了個(gè)咪 我要登陸', pwd='123456'}
05-24 13:22:22.835 2314-2622/com.tiny.demo.firstlinecode E/tiny_module: AsyncToSyncActivity 登錄請(qǐng)求成功: sub Thread,name --> RxCachedThreadScheduler-2
05-24 13:22:22.836 2314-2623/com.tiny.demo.firstlinecode E/AsyncToSyncActivity: 登錄響應(yīng) loginRespBean:LoginRespBean{name='貓了個(gè)咪 我要登陸', 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='貓了個(gè)咪 我要登陸', 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——多個(gè)異步任務(wù)執(zhí)行完畢后在執(zhí)行目標(biāo)任務(wù)

等待多個(gè)任務(wù)完成后再執(zhí)行目標(biāo)任務(wù),不保證順序。

    public void onBtnJavaRxjavaMergeClicked() {
        /**
         * 等待多個(gè)任務(wù)完成后再執(zhí)行,不保證順序
         */
        Observable o1 = Observable.create((ObservableOnSubscribe<String>) e -> {
            ThreadUtils.logCurrThreadName(TAG + " Observable1");
            TimeUnit.SECONDS.sleep(5);
            e.onNext("第一個(gè)Observable");
            e.onComplete();
        }).subscribeOn(Schedulers.newThread());

        Observable o2 = Observable.create((ObservableOnSubscribe<String>) e -> {
            ThreadUtils.logCurrThreadName(TAG + " Observable2");
            TimeUnit.SECONDS.sleep(3);
            e.onNext("第二個(gè)Observable");
            e.onComplete();
        }).subscribeOn(Schedulers.newThread());

        Observable o3 = Observable.create((ObservableOnSubscribe<String>) e -> {
            ThreadUtils.logCurrThreadName(TAG + " Observable3");
            TimeUnit.SECONDS.sleep(1);
            e.onNext("第三個(gè)Observable");
            e.onComplete();
        }).subscribeOn(Schedulers.newThread());

        /**
         * 三個(gè)任務(wù)都發(fā)送了onComplete事件后,訂閱者的onComplete方法才會(huì)調(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: 第三個(gè)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: 第二個(gè)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: 第一個(gè)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

當(dāng)三個(gè)Observable都發(fā)送了onComplete事件后,Observer的onComplete方法才會(huì)調(diào)用。

 到此這篇關(guān)于Java實(shí)現(xiàn)異步轉(zhuǎn)同步的多種方法介紹的文章就介紹到這了,更多相關(guān)Java異步轉(zhuǎn)同步內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

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

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

    這篇文章主要為大家介紹了Java中的函數(shù)式接口,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助<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 項(xiàng)目中,表示客戶端與服務(wù)端的 HTTP 請(qǐng)求連接被中斷,接下來由小編給大家介紹一下出現(xiàn)這個(gè)問題的原因,需要的朋友可以參考下
    2024-12-12
  • Java模擬并解決緩存穿透問題

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

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

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

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

    詳解Java Selenium中的鼠標(biāo)控制操作

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

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

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

    Linux 安裝 Oracle Java 8的步驟詳解

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

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

    SimpleDateFormat 就是一個(gè)典型的線程不安全事例,本文主要介紹了解決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)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • java圖的深度優(yōu)先遍歷實(shí)現(xiàn)隨機(jī)生成迷宮

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

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

最新評(píng)論

临海市| 昌吉市| 蓬莱市| 团风县| 吴桥县| 襄汾县| 阳东县| 大城县| 同心县| 光泽县| 涟源市| 城固县| 富锦市| 南康市| 平远县| 简阳市| 江华| 杭锦后旗| 娄底市| 黑龙江省| 耒阳市| 岳池县| 察雅县| 澄城县| 托里县| 裕民县| 衡阳县| 井陉县| 武强县| 元朗区| 永寿县| 平昌县| 红桥区| 甘肃省| 浦县| 潮安县| 武邑县| 伊川县| 海城市| 日土县| 武汉市|