Java多线程简单实现取消和进度
来源:互联网 发布:MySQL和oracle的count 编辑:程序博客网 时间:2024/06/10 05:08
Java中简单实现多线程调度时的可取消和显示进度
一个简单的多线程调度实现,统一开始,为了使得所有线程统一开始,类似运动员在听到发令枪时一起进行,使用了CountDownLatch进行控制。
CountDownLatch beginLatch = new CountDownLatch(1);CountDownLatch endLatch = new CountDownLatch(personCount);
主线程建立线程池,并进行调度,由于要在最后进行汇总结果,使用了FutureTask
List<FutureTask<String>> futureTaskList = new ArrayList<FutureTask<String>>();for (int i = 0; i < personCount; i++) {futureTaskList.add(new FutureTask<String>(new ExecuteCallable(beginLatch, endLatch,i)));}ExecutorService execService = Executors.newFixedThreadPool(threadCount);for (FutureTask<String> futureTask : futureTaskList) {execService.execute(futureTask);}beginLatch.countDown();
这样所有线程就会统一开始执行,执行完成后,汇总结果,并关闭线程池。
endLatch.await();System.out.println("--------------");for (FutureTask<String> futureTask : futureTaskList) {System.out.println(futureTask.get());}execService.shutdown();
对于每个线程的执行,都需要共享变量beginLatch和endLatch,各线程代码:
public class ExecuteCallable implements Callable<String> {private int id;private CountDownLatch beginLatch;private CountDownLatch endLatch;public ExecuteCallable(CountDownLatch beginLatch, CountDownLatch endLatch,Exchanger<Integer> exchanger, int id,ConcurrentTaskExecutor concurrentTaskExecutor) {this.beginLatch = beginLatch;this.endLatch = endLatch;this.id = id;}@Overridepublic String call() throws Exception {beginLatch.await();long millis = (long) (Math.random() * 10 * 1000);String result = String.format("Player :%s arrived, use %s millis", id, millis);Thread.sleep(millis);System.out.println(result);endLatch.countDown();return result;}}
每个线程在开始等待发令枪(beginLatch),随机等待一段时间(模拟执行时间),最后通知endLatch减一(执行完毕通知),并返回结果。
到这里只是一个简单的实现,我们并不能在主线程中实时了解各线程的执行情况,除非到了所有线程执行完毕(endLatch解除阻塞状态)。这时候我们使用Exchanger机制来进行线程之间数据的交换,在每个线程执行完成后,将其完成的数据量传给主线程进行刷新(模拟进度条工作)。
主线程ConcurrentTaskExecutor类中:
Exchanger<Integer> exchanger = new Exchanger<Integer>();beginLatch.countDown();Integer totalResult = Integer.valueOf(0);for (int i = 0; i < personCount; i++) {Integer partialResult = exchanger.exchange(Integer.valueOf(0)); if(partialResult != 0){ totalResult = totalResult + partialResult;System.out.println(String.format("Progress: %s/%s", totalResult, personCount));}}endLatch.await();
线程类ExecuteCallable构造函数加入exchanger
@Overridepublic String call() throws Exception { beginLatch.await();long millis = (long) (Math.random() * 10 * 1000);String result = String.format("Player :%s arrived, use %s millis", id, millis);Thread.sleep(millis);System.out.println(result);exchanger.exchange(1);endLatch.countDown();return result;}
在执行完成进行数据交换,返回本次执行进度给主线程(当前默认设置成1,可修改),主线程在所有线程执行完成前,endLatch.await()必定是阻塞状态的,这样主线程就能实时拿到子线程执行完成的进度数据。
下面我们再加入一个可以取消的功能,加入系统随机在某个时间点进行取消操作,那么开始执行的线程是无法进行实时响应了,只能等待当前操作执行完毕;如果线程还没有开始执行,那么就取消其行为。
更改的ExecuteCallable执行方法如下:
@Overridepublic String call() throws Exception {beginLatch.await();if(concurrentTaskExecutor.isCanceled()){endLatch.countDown();exchanger.exchange(0);return String.format("Player :%s is given up", id);}long millis = (long) (Math.random() * 10 * 1000);String result = String.format("Player :%s arrived, use %s millis", id, millis);Thread.sleep(millis);System.out.println(result);exchanger.exchange(1);endLatch.countDown();return result;}
其中concurrentTaskExecutor类中加入一个类型为boolean的canceled变量,注意这个变量必须是volatile的,以便能够在线程间共享数据,并且该变量的setter和getter方法也是原子性的。
我们的取消操作不能放在主线程中操作,需要额外建立一个线程,并且这个线程也不能通过线程池进行调度,新建的InterruptRunnable类:
public class InterruptRunnable implements Runnable {private CountDownLatch beginLatch;private ConcurrentTaskExecutor concurrentTaskExecutor;public InterruptRunnable(ConcurrentTaskExecutor currConcurrentTaskExecutor, CountDownLatch beginLatch) {this.beginLatch = beginLatch;this.concurrentTaskExecutor = currConcurrentTaskExecutor;}@Overridepublic void run() {try {beginLatch.await();long millis = (long) (Math.random() * 10 * 1000);System.out.println(String.format("System need sleep %s millis", millis));Thread.sleep(millis);} catch (InterruptedException e) {e.printStackTrace();}concurrentTaskExecutor.setCanceled(true);}}
更改后的ConcurrentTaskExecutor,在执行发令前,先让该中断线程启动,以便一起等待开始命令:
new Thread(new InterruptRunnable(this, beginLatch)).start();beginLatch.countDown();
最后执行结果(取决于中断线程的随机时间长短):
System need sleep 2920 millisPlayer :4 arrived, use 917 millisProgress: 1/10Player :5 arrived, use 1076 millisProgress: 2/10Player :3 arrived, use 2718 millisProgress: 3/10Player :1 arrived, use 4013 millisProgress: 4/10Player :0 arrived, use 8541 millisProgress: 5/10Player :2 arrived, use 8570 millisProgress: 6/10Player :6 arrived, use 7261 millisProgress: 7/10Player :7 arrived, use 7015 millisProgress: 8/10--------------Player :0 arrived, use 8541 millisPlayer :1 arrived, use 4013 millisPlayer :2 arrived, use 8570 millisPlayer :3 arrived, use 2718 millisPlayer :4 arrived, use 917 millisPlayer :5 arrived, use 1076 millisPlayer :6 arrived, use 7261 millisPlayer :7 arrived, use 7015 millisPlayer :8 is given upPlayer :9 is given up
最后,附上最终的程序代码
ConcurrentTaskExecutor:
public class ConcurrentTaskExecutor {private volatile boolean canceled = false;public void executeTask() throws Exception {int personCount = 10;int threadCount = 5;CountDownLatch beginLatch = new CountDownLatch(1);CountDownLatch endLatch = new CountDownLatch(personCount);Exchanger<Integer> exchanger = new Exchanger<Integer>();List<FutureTask<String>> futureTaskList = new ArrayList<FutureTask<String>>();for (int i = 0; i < personCount; i++) {futureTaskList.add(new FutureTask<String>(new ExecuteCallable(beginLatch, endLatch, exchanger, i, this)));}ExecutorService execService = Executors.newFixedThreadPool(threadCount);for (FutureTask<String> futureTask : futureTaskList) {execService.execute(futureTask);}new Thread(new InterruptRunnable(this, beginLatch)).start();beginLatch.countDown();Integer totalResult = Integer.valueOf(0);for (int i = 0; i < personCount; i++) {Integer partialResult = exchanger.exchange(Integer.valueOf(0));if(partialResult != 0){totalResult = totalResult + partialResult;System.out.println(String.format("Progress: %s/%s", totalResult, personCount));}}endLatch.await();System.out.println("--------------");for (FutureTask<String> futureTask : futureTaskList) {System.out.println(futureTask.get());}execService.shutdown();}public boolean isCanceled() {return canceled;}public void setCanceled(boolean canceled){this.canceled = canceled;}public static void main(String[] args) throws Exception {ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor();executor.executeTask();}}
ExecuteCallable
public class ExecuteCallable implements Callable<String> {private int id;private CountDownLatch beginLatch;private CountDownLatch endLatch;private Exchanger<Integer> exchanger;private ConcurrentTaskExecutor concurrentTaskExecutor;public ExecuteCallable(CountDownLatch beginLatch, CountDownLatch endLatch,Exchanger<Integer> exchanger, int id,ConcurrentTaskExecutor concurrentTaskExecutor) {this.beginLatch = beginLatch;this.endLatch = endLatch;this.exchanger = exchanger;this.id = id;this.concurrentTaskExecutor = concurrentTaskExecutor;}@Overridepublic String call() throws Exception {beginLatch.await();if(concurrentTaskExecutor.isCanceled()){endLatch.countDown();exchanger.exchange(0);return String.format("Player :%s is given up", id);}long millis = (long) (Math.random() * 10 * 1000);String result = String.format("Player :%s arrived, use %s millis", id, millis);Thread.sleep(millis);System.out.println(result);exchanger.exchange(1);endLatch.countDown();return result;}}
InterruptRunnable
public class InterruptRunnable implements Runnable {private CountDownLatch beginLatch;private ConcurrentTaskExecutor concurrentTaskExecutor;public InterruptRunnable(ConcurrentTaskExecutor currConcurrentTaskExecutor, CountDownLatch beginLatch) {this.beginLatch = beginLatch;this.concurrentTaskExecutor = currConcurrentTaskExecutor;}@Overridepublic void run() {try {beginLatch.await();long millis = (long) (Math.random() * 10 * 1000);System.out.println(String.format("System need sleep %s millis", millis));Thread.sleep(millis);} catch (InterruptedException e) {e.printStackTrace();}concurrentTaskExecutor.setCanceled(true);}}
- Java多线程简单实现取消和进度
- android简单实现多线程,断点下载和状态栏下载进度
- 进度和取消
- Java下载器的简单实现及实时进度和速度获取
- Java动态显示文件上传进度的简单实现
- Java动态显示文件上传进度的简单实现
- Java动态显示文件上传进度的简单实现
- 简单使用AFN实现下载和查看进度
- [Java] 多线程的简单实现
- JAVA 多线程的简单实现
- JAVA多线程简单实现方法
- JAVA实现的简单多线程
- java简单的多线程实现
- js实现简单的checkbox全选和取消全选效果
- Java带进度多线程下载文件
- 用java实现简单的多线程下载
- Java多线程 Web服务器简单实现
- 用JAVA实现简单爬虫多线程抓取
- 关于母函数
- 在多线程中捕获并处理RuntimeException
- LTE物理传输资源(2)-频带、信道带宽和频点号EARFCN
- 上传图片到服务器系列之----前后台路径获取问题
- gdb调试小案例
- Java多线程简单实现取消和进度
- Aspose表格中单元格写入问题
- 使用Tycho构建OSGi插件项目
- BZOJ 4807(車-高精度)
- RTP/RTCP/RTSP/SIP/SDP 关系
- win7 系統下 安裝apache
- JIRA系统的设置和使用
- Python--Mysql连接池使用案例
- Bootstrap 实例