有时,为了程序的性能,我们有必要对程序中的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); } }
相关推荐
在多线程编程中,"子线程更新主线程数据"是一个常见的需求,尤其是在UI界面交互和后台处理相结合的应用中。主线程通常负责用户界面的显示与交互,而子线程则用于执行耗时的任务,避免阻塞主线程,提供良好的用户体验...
在Winform应用中,我们可以创建一个新的后台线程(子线程)来执行数据获取任务,同时确保主线程保持响应,更新UI。以下是一般的步骤: 1. **定义异步方法**:首先,你需要定义一个返回`Task`的异步方法,用于执行...
- **事件对象(Event)**:创建一个事件对象,子线程完成任务后设置事件状态,主线程等待该事件,接收到通知后处理数据。 - **消息队列(Message Queue)**:子线程可以通过PostMessage或SendMessage函数向主线程...
在这个场景下,我们可以通过委托或.NET框架提供的Action和Func泛型委托来传递回调函数,从而让子线程在完成后调用主线程定义的方法。 下面是一个使用自定义委托的例子: ```csharp public delegate void Entrust...
在Java多线程环境中,让主线程等待所有子线程执行完毕是一个常见的需求,尤其是在处理大量数据或进行高性能计算时。这不仅有助于正确测量整体执行时间,还能够确保资源的正确释放和数据的一致性。 #### 详细解析 *...
4. **示例代码**:以下是一个简单的例子,演示了如何使用观察者模式来实现子线程通知主线程: ```java import java.util.Observable; import java.util.Observer; class WorkerThread extends Observable ...
子线程任务发生异常,主线程事务如何回滚? 本文将详细探讨当子线程任务发生异常时,如何让主线程捕获到该异常并进行事务的回滚。下面将从多线程编程的基础知识、线程池的使用、异常捕获三个方面进行阐述。 一、多...
"主线程等待子多线程(无结果返回)执行完成再继续执行"这个主题就涉及到如何在Java、C#、Python等编程语言中实现这种同步机制。下面将详细讨论这个知识点。 **1. Java中的`Thread.join()`方法** 在Java中,主线程...
JAVA 主线程等待子线程执行完毕再执行 JAVA 中的线程控制是非常重要的一部分,而在实际开发中,我们经常会遇到需要主线程等待子线程执行完毕再执行的情况。这种情况下,我们可以使用两种方式来实现:主动式和被动式...
Java 主线程等待子线程执行完毕 Java 中的多线程编程是非常重要的一部分,特别是在需要并发执行多个任务的情况下。然而,在某些情况下,我们需要等待所有子线程执行完毕后再继续执行主线程的剩余动作。这时,我们...
c#子线程如何读取及设置主线程ui的值,自己录的一个小视频,方便理解,比较菜鸟的方法,请勿喷!
`Thread.join()`方法允许主线程等待一个特定的子线程执行完成。一旦调用了`join()`,主线程会被阻塞,直到被调用的线程执行完毕。例如: ```java Thread childThread = new Thread(() -> { // 子线程的代码 }); ...
C#子线程刷新主线程示例源码 功能介绍: 使用线程操作 1、实时显示当前时间 2、输入加数和被加数,自动出现结果 技术特点: 使用了多线程实现了子线程刷新主线程 ,使用委托刷新主线程。 注意: 开发环境为...
Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码...
Unity除了一些基本的数据类型,几乎所有的API都不能在子线程中调用,如果项目中有一段很耗时操作,unity可能会出现“卡死...因此针对这个问题再加上查找了一些资料,弄出了一个小工具,可以子线程与主线程的相互访问。
在多线程编程中,子线程与主线程的交互是一个常见的需求,特别是在GUI应用程序中。主线程通常负责用户界面的更新和事件处理,而子线程则用于执行耗时的任务,以避免阻塞UI。本示例将深入探讨如何在Java或C#等支持多...
要解决“让主线程等待所有子线程执行完毕”的问题,可以采用以下策略: 1. 使用`join()`方法:如提到的,直接在每个子线程的`start()`之后调用`t.join()`,会导致所有线程按顺序执行。这是因为`join()`会让主线程...
6. **处理消息**:子线程的Handler会在其Looper的消息循环中接收到主线程发送的消息,然后通过`handleMessage()`方法处理这个消息。 在压缩包文件"Looper2"中,可能包含了一个示例代码或者相关的资源,用于演示如何...
主线程中,我们连接这个信号到一个槽函数,该槽函数将在主线程中运行,并更新QTableWidget。 以下是一个简单的实现步骤: 1. **创建信号**:在子线程类中,定义一个信号,例如`dataReady`,它可能携带处理好的数据...
子线程则常用于执行长时间运行的任务,以避免阻塞UI。但直接在子线程中修改UI控件可能导致未定义的行为,因为这些控件是由主线程创建和管理的。为了解决这个问题,我们需要使用特定的方法来委托更新给主线程。 首先...