有时,为了程序的性能,我们有必要对程序中的for循环(含有sql/rpc操作)进行并发处理,要求是并发处理完之后才能继续执行主线程。现给出如下两种方案:
1. CountDownLatch
package com.itlong.whatsmars.base.sync; import java.util.concurrent.CountDownLatch; /** * Created by shenhongxi on 2016/8/12. */ public class CountDownLatchTest { public static void main(String[] args) { CountDownLatch latch = new CountDownLatch(3); long start = System.currentTimeMillis(); for (int i = 0; i < 3; i++) { new Thread(new SubRunnable(i, latch)).start(); } try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(System.currentTimeMillis() - start); System.out.println("Main finished"); } static class SubRunnable implements Runnable { private int id = -1; private CountDownLatch latch; SubRunnable(int id, CountDownLatch latch) { this.id = id; this.latch = latch; } @Override public void run() { try { Thread.sleep(3000); System.out.println(String .format("Sub Thread %d finished", id)); } catch (InterruptedException e) { e.printStackTrace(); } finally { latch.countDown(); } } } }
CountDownLatch用队列来存放任务,主要是一个构造器和两个方法,相关代码这里不予赘述。CountDownLatch很贴合我们的要求,但没用到线程池,而且latch是只提供了计数功能然后子线程的逻辑有没有可能会在主线程逻辑之后执行??,综合考虑,我推荐下面的这种方案。
2. ExecutorService
package com.itlong.whatsmars.base.sync; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by shenhongxi on 2016/8/12. */ public class CallableTest { public static void main(String[] args) throws Exception { ExecutorService pool = Executors.newFixedThreadPool(3); List<Callable<Void>> subs = new ArrayList<Callable<Void>>(); for (int i = 0; i < 3; i++) { subs.add(new SubCallable(i)); } long start = System.currentTimeMillis(); try { pool.invokeAll(subs); } finally { pool.shutdown(); } System.out.println(System.currentTimeMillis() - start); System.out.println("Main finished"); } static class SubCallable implements Callable<Void> { private int id = -1; public SubCallable(int id) { this.id = id; } @Override public Void call() throws Exception { try { Thread.sleep(3000); System.out.println(String .format("Child Thread %d finished", id)); } catch (InterruptedException e) { e.printStackTrace(); } return null; } } }
AbstractExecutorService
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException { if (tasks == null) throw new NullPointerException(); List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size()); boolean done = false; try { for (Callable<T> t : tasks) { RunnableFuture<T> f = newTaskFor(t); futures.add(f); execute(f); } for (Future<T> f : futures) { if (!f.isDone()) { try { f.get(); } catch (CancellationException ignore) { } catch (ExecutionException ignore) { } } } done = true; return futures; } finally { if (!done) for (Future<T> f : futures) f.cancel(true); } }
接下来我做了个join的试验,发现同样可以达到目的,但不推荐此法。
package com.itlong.whatsmars.base.sync; /** * Created by shenhongxi on 2016/8/12. * 子线程与主线程是顺序执行的,各子线程之间还是异步的 */ public class JoinTest { public static void main(String[] args) throws Exception { Thread t1 = new Thread(new SubRunnable(0)); Thread t2 = new Thread(new SubRunnable(1)); Thread t3 = new Thread(new SubRunnable(2)); long start = System.currentTimeMillis(); t1.start(); t2.start(); t3.start(); t1.join(); t2.join(); t3.join(); System.out.println(System.currentTimeMillis() - start); System.out.println("Main finished"); } static class SubRunnable implements Runnable { private int id = -1; SubRunnable(int id) { this.id = id; } @Override public void run() { try { System.out.println("hi, I'm id-" + id); Thread.sleep(9000); System.out.println(String .format("Sub Thread %d finished", id)); } catch (InterruptedException e) { e.printStackTrace(); } } } }
最后,我们顺便提下org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport implements SchedulingTaskExecutor { private final Object poolSizeMonitor = new Object(); private int corePoolSize = 1; private int maxPoolSize = Integer.MAX_VALUE; private int keepAliveSeconds = 60; private boolean allowCoreThreadTimeOut = false; private int queueCapacity = Integer.MAX_VALUE; private ThreadPoolExecutor threadPoolExecutor; /** * Set the ThreadPoolExecutor's core pool size. * Default is 1. * <p><b>This setting can be modified at runtime, for example through JMX.</b> */ public void setCorePoolSize(int corePoolSize) { synchronized (this.poolSizeMonitor) { this.corePoolSize = corePoolSize; if (this.threadPoolExecutor != null) { this.threadPoolExecutor.setCorePoolSize(corePoolSize); } } } /** * Return the ThreadPoolExecutor's core pool size. */ public int getCorePoolSize() { synchronized (this.poolSizeMonitor) { return this.corePoolSize; } }
看到我们熟悉的ThreadPoolExecutor之后,我们瞬间明白了一切。
另外我们脑补下几个接口/类的关系
public interface ExecutorService extends Executor { <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException; } public interface Executor { void execute(Runnable command); } public abstract class AbstractExecutorService implements ExecutorService{ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) { // ... } } public class ThreadPoolExecutor extends AbstractExecutorService { public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); } }
相关推荐
子线程更新主线程数据(再谈多线程)
C# Winfrom必须掌握的技术,主线程显示数据,子线程获取数据,这是我做项目实际用到的技术。
下面小编就为大家带来一篇C#子线程执行完后通知主线程的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
java 子线程通过观察者模式通知主线程
Java多线程--让主线程等待所有子线程执行完毕
c#子线程如何读取及设置主线程ui的值,自己录的一个小视频,方便理解,比较菜鸟的方法,请勿喷!
C#子线程刷新主线程示例源码 功能介绍: 使用线程操作 1、实时显示当前时间 2、输入加数和被加数,自动出现结果 技术特点: 使用了多线程实现了子线程刷新主线程 ,使用委托刷新主线程。 注意: 开发环境为...
本资源详细介绍了主线程和子线程之间的通信过程,通过实例讲解了参数如何传递
Unity除了一些基本的数据类型,几乎所有的API都不能在子线程中调用,如果项目中有一段很耗时操作,unity可能会出现“卡死...因此针对这个问题再加上查找了一些资料,弄出了一个小工具,可以子线程与主线程的相互访问。
Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码...
子线程任务发生异常,主线程事务如何回滚
Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程执行完的五种方法 Java多线程--等待所有子线程...
Handler消息传递详解,子线程到子线程,主线程到子线程,子线程到主线程 三种消息,Looper,Handler工作机制详解 https://blog.csdn.net/shoneworn/article/details/80447651
1。 子线程操作主线程的示例 2。 全部源代码
我就废话不多说了,还是直接看代码吧! from time import ctime import threading import time def a(): #for i in range(5): print('Program a is running... at ', ctime(),u'.... time.sleep(0.2) ...
Java主线程等待所有子线程执行完毕在执行,其实在我们的工作中经常的用到,本篇文章就介绍了Java多线程--让主线程等待所有子线程执行完毕在执行,有需要的可以了解一下。
通过窗口传递让主线程触发FIRE事件(子线程不能触发)
非常实用不解释,用了才知道 个人收藏的一部分资料将陆续给大家上传
我在工作的过程中遇到一个问题,需要主线程等等所有子线程执行完后再做某件事情,在网上找了很多代码,都没有真正解决这个问题. 现在我解决了这个问题,把代码共享出来供大家参考. 代码中有注释和注意事项,相信大家看过...
下面小编就为大家分享一篇Java父线程(或是主线程)等待所有子线程退出的实例,具有很好的参考价值,希望对大家有所帮助