「并发」实际开发中的应用方式

64 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

Callable+future

想要获取到所有的线程执行结果。等待所有线程执行结束了计算线程中执行的成功数量

class CallableFutureDemo1 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        int num = 10;
        List<FutureTask<String>> list = new ArrayList<>();
        while (num > 0) {
            num--;
            int finalNum = num;
            FutureTask<String> task = new FutureTask<String>(() -> {
                System.out.println("Callable-call-" + finalNum);
                Thread.sleep(1000);
                return finalNum + "执行完了";
            });
            task.run();
            list.add(task);
        }
        list.forEach(task -> {
            try {
                System.out.println(task.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });
    }
}

class CallableDemo implements Callable {
    @Override
    public Object call() throws Exception {

        System.out.println("Callable-call执行了");
        Thread.currentThread().wait(3000);
        return true;
    }
}

线程池执行

可以将Future全部获取到存入List中,在所有任务全部派发出去之后再遍历list获取结果进行get来等待线程执行结束的结果(因为存入和取出futureTask都是顺序的,所以不会影响效率。)一般都是在最后一个任务执行完成主线程也等待到了所有线程的执行结果

class CallableFutureDemo2ThreadPool {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        int num = 1000;
        List<Future<Integer>> list = new ArrayList<>();
        while (num > 0) {
            num--;
            int finalNum = num;
            Future<Integer> submit = executorService.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    long currentTimeMillis = System.currentTimeMillis();
                    Thread.sleep(1000);
                    System.out.println("Thread:" + Thread.currentThread().getId() + "deal num:" + finalNum + "任务");
                    return Integer.valueOf((int) (System.currentTimeMillis() - currentTimeMillis));
                }
            });
            list.add(submit);
        }

        list.forEach(task -> {
            try {
                System.out.println(task.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });


    }
}

CountDownLatch

获取线程执行结果。计数器,使用await()方法时,只有计数到0才结束阻塞操作

第一步:创建CountDownLatch对象CountDownLatch latch=new CountDownLatch(THREAD_LATCH_SIZE)同时指定计数器的大小。

第二步:在每个线程执行结束的时候调用latch.countDown()方法进行自减1。

第三步:在主线程需要等待所有线程执行结束的地方调用latch.await()方法触发阻塞操作。

    public static void main(String[] args) throws InterruptedException {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.initialize();
        //真实项目中使用需要配置其中的参数taskExecutor,只是做个表示
        taskExecutor.setCorePoolSize(100);
        //计数器=任务数
        CountDownLatch latch = new CountDownLatch(TASK_SIZE);
        int num = TASK_SIZE;
        while (num > 0) {
            num--;
            taskExecutor.submit(() -> {
                System.out.println("线程:" + Thread.currentThread().getId() + "执行结束啦");
                latch.countDown();
            });
        }
        //等待计数器计数结束,如果超过设置的时间不结束就结束等待阻塞
        latch.await(60, TimeUnit.SECONDS);
        System.out.println("终于等到你");
    }

CountDownLatch的原理就是使用AQS进行一个自变量status的管理(自减)所以能做到线程安全及同步