java 当前线程 等待_Java 多线程等待
背景
在一些场景中,我们需要获取多份数据,而这些数据获取的先后顺序是无关的,我们只需要把数据收集齐,然后再对这些数据统一处理。
比如:执行两个任务 task1 和 task2,都执行完毕后,再把两个任务的结果相加。
例如执行 task1 需要 1s,执行 task2 需要 2s,顺序执行,那么总时间是 1s + 2s = 3s。而如果我们用异步的方式,task1 和 task2 同时执行,则能减少响应的时间。
但并行的方式则必须注意,需要等待所有任务执行完毕之后,才能计算最终的结果,因此这就涉及多线程之间的等待。
方案一:Future.get() 获取数据
先创建一个线程池,并使用 ExecutorService.submit() 方法提交两个 Callable 任务。
提交任务后,这俩任务将开始异步并行执行,并返回了 Future 类型的对象,代表一个未来能获取结果的对象。
当我们调用 Future 对象的 get() 方法时,如果提交的任务已经完成,我们就直接获得结果。如果异步任务还没有完成,那么 get() 会阻塞当前线程,直到所有任务都完成后,才能获得执行的结果。
注意:当 submit() 时,任务就已经开始执行,但不会阻塞线程,当 get() 时,如果还有未完成的任务,才会阻塞当前主线程的运行,直到所有任务都完成后,才能获得执行的结果。
void executorServiceExample() throws Exception {
long time1 = System.currentTimeMillis();
// 任务1
Callable task1 = () -> {
Thread.sleep(1000);
return 10;
};
// 任务2
Callable task2 = () -> {
Thread.sleep(2000);
return 20;
};
// 创建线程池
ExecutorService service = Executors.newFixedThreadPool(2);
// 提交任务2个任务
Future submit1 = service.submit(task1);
Future submit2 = service.submit(task2);
// 获取任务结果,由于任务还未执行完毕,因此下一行将阻塞当前线程,直到所有任务都执行完毕
Integer result1 = submit1.get();
Integer result2 = submit2.get();
System.out.println("总耗时:" + (System.currentTimeMillis() - time1)); // 总耗时:2012
System.out.println(result1 + result2); // 30
service.shutdown();
}
方案二:CountdownLatch
CountdownLatch 用来控制一个或者多个线程等待多个线程。
维护了一个计数器 cnt,每次调用 countDown() 方法会让计数器的值减 1,减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。
CountdownLatch 计数方法
void countdownLatchExample() throws InterruptedException {
long time = System.currentTimeMillis();
// 创建 CountDownLatch,计数为2
CountDownLatch countDownLatch = new CountDownLatch(2);
// 创建线程池
ExecutorService executorService = Executors.newCachedThreadPool(2);
// 任务1
Runnable task1 = () -> {
System.out.println("begin task 1");
Thread.sleep(1000); // 省略 try-catch
System.out.println("end task 1");
countDownLatch.countDown(); // 计数减1
};
// 任务2
Runnable task2 = () -> {
System.out.println("begin task 2");
Thread.sleep(2000); // 省略 try-catch
System.out.println("end task 2");
countDownLatch.countDown(); // 计数减1
};
// 并行执行任务
executorService.execute(task1);
executorService.execute(task2);
// 等待2个任务执行完毕,countDownLatch计数器为0,才往下执行
countDownLatch.await();
System.out.println("total time: " + (System.currentTimeMillis() - time));
executorService.shutdown();
}
方案三:CyclicBarrier
CyclicBarrier 用来控制多个线程互相等待,只有当多个线程都到达时,这些线程才会继续执行。
和 CountdownLatch 相似,都是通过维护计数器来实现的。线程执行 await() 方法之后计数器会减 1,并进行等待,直到计数器为 0,所有调用 await() 方法而在等待的线程才能继续执行。
CyclicBarrier 计数方法
CyclicBarrier 和 CountdownLatch 的一个区别是:
1、CyclicBarrier 的计数器通过调用 reset() 方法可以循环使用,所以它才叫做循环屏障。
2、countDownLatch.countDown() 只会将计数减 1,不会阻塞当前线程,countDownLatch.await() 只会阻塞当前线程,不会减少计数;而cyclicBarrier.await() 既会阻塞当前线程,也会计数减1。
CyclicBarrier 有两个构造函数,其中 parties 指示计数器的初始值,barrierAction 当计数为0时回调该方法。
void cyclicBarrierExample() {
long time = System.currentTimeMillis();
// 创建CyclicBarrier,计数为2,当计数为0时会回调该方法
CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> {
System.out.println("all task end");
System.out.println("total time: " + (System.currentTimeMillis() - time));
});
// 创建线程池
ExecutorService executorService = Executors.newCachedThreadPool();
// 任务1
Runnable task1 = () -> {
System.out.println("begin task 1");
Thread.sleep(1000); // 省略 try-catch
System.out.println("end task 1");
cyclicBarrier.await(); // 计数减1并阻塞当前线程,省略了try-catch
};
// 任务2
Runnable task2 = () -> {
System.out.println("begin task 2");
Thread.sleep(2000); // 省略 try-catch
System.out.println("end task 2");
cyclicBarrier.await(); // 计数减1并阻塞当前线程,省略了try-catch
};
executorService.execute(task1);
executorService.execute(task2);
executorService.shutdown();
}
java 当前线程 等待_Java 多线程等待相关推荐
- JAVA:线程总结及多线程实现的两种方法
JAVA:线程总结 目录 目录 JAVA:线程总结 JAVA:线程总结 01_多线程(多线程的引入)(了解) 02_多线程(多线程并行和并发的区别)(了解) 03_多线程(Java程序运行原理和JVM ...
- java 线程等待队列_Java多线程学习(五)——等待通知机制
等待通知机制的实现 方法wait()的作用是使当前线程进行等待,wait()方法是Object类的方法,该方法用来将当前线程放到"预执行队列",并在wait()所在的代码处停止执行 ...
- java线程入门_java多线程快速入门(一)
1.什么是进程 比如:QQ.QQ游戏.eclipse都是进程,可以通过任务管理器查看进程 2.进程和线程区别 线程是进程的一部分,一个进程可以包含多个线程,一个线程只能属于一个进程 进程是所有线程的集 ...
- java 线程 组成_java多线程
一:基本知识点 1.1线程与进程区别: 1.进程是资源分配的最小单位,线程是CPU调度的最小单位 2.一个进程由一个或多个线程组成 3.进程之间相互独立,每个进程都有独立的代码和数据空间,但同一进程下 ...
- java中让步的_java 多线程—— 线程让步
java 多线程 目录: 概述 第1 部分 yield()介绍 yield()的作用是让步.它能让当前线程由"运行状态"进入到"就绪状态",从而让其它具有相同优 ...
- thread.sleep是让哪个线程休眠_java多线程必看:java线程的生命周期
点击蓝字 关注我们 线程是一个动态执行的过程,它也有从创建到死亡的过程.线程的几种状态 在 Thread 类中,有一个枚举内部类: 上面的信息以图片表示如下: 第一张图: 第二张图:把等待.计时等待. ...
- java线程名_java多线程
首先讲一下进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程. 线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈 ...
- java 线程简介_java多线程介绍
java多线程介绍 多线程的基本实现 进程指运行中的程序,每个进程都会分配一个内存空间,一个进程中存在多个线程,启动一个JAVA虚拟机,就是打开个一个进程,一个进程有多个线程,当多个线程同时进行,就叫 ...
- java线程基础_Java多线程基础
前言 在我们工作和学习的过程中,Java线程我们或多或少的都会用到,但是在使用的过程上并不是很顺利,会遇到各种各样的坑,这里我通过讲解Thread类中的核心方法,以求重点掌握以下关键技术点: 线程的启 ...
最新文章
- BestCoder Round #65 B C D || HDU 5591 5592 5593
- mysql 没有mysql库_MySQL安装之后没有MySQL数据库的原因
- Hive的安装和配置
- oracle中偏移,怎么对相同的坐标点偏移?
- 关于面试宝典中的各个问题(一)
- nohup xxx 后台进程关闭,可以这样避免
- 输入输出Fibonacci数
- [POJ3177]Redundant Paths(双联通)
- 华为P40或将搭载鸿蒙,华为P40或将在明年3月发布,很有可能是首部搭载鸿蒙的手机...
- matlab 0到正无穷求和,1/k!k从0到无穷求和是多少
- 远程桌面管理工具RDCMan
- pytest+seleniumUI自动化框架设计
- 顺势腹式呼吸还是逆势
- 【C语言编程练习】华氏转换为摄氏
- Android渲染时间 太长,Android性能优化之渲染篇
- 有道身份证查询接口API
- R语言—90分钟从入门到精通
- 移动硬盘读不出来,无法识别的6种修复方法
- android 编程词典,基于Android的英文词典的实现方法
- 使用python爬虫爬取百度新闻,告诉你社会热点话题