问题引出:
我们对数据库的操作是一个耗时过程,假如我们需要让数据库批量操作完成之后,再跳转到另外一个页面,注意:是批量操作完成之后再跳转。
分析:以上需求我们遇到2个难点,
第一个难点是怎么控制并发问题,
第二个难点是怎么使主线程等待所有子线程完成之后再执行。
首先,我们先解决并发问题,其实,在jdk1.5的时候,java大牛Doug Lea线程已经解决了这个问题,我们今天就借用Doug Lea先生的API来解决这个问题。如下是详细解释和源码:
- <span style="font-size:12px;">package com.bzjy.thread;
- import java.util.concurrent.Semaphore;
- import java.util.concurrent.atomic.AtomicInteger;
- public class ThreadTest {
- private static Semaphore semaphore = new Semaphore(5);// 设置并发信号量为5
- private static AtomicInteger atomicInteger = new AtomicInteger(0);// 声明原子操作整数,初始化为9
- public static void main(String[] args) {
- <span style="color:#009900;">// 首先介绍一个并发工具包,Semphore(信号量)
- // 这里我们需要用到它的代参构造Semaphore semaphore = new Semaphore(permits);
- // 参数permits的意思是同时可以存在多少个信号,或者说是同时可以并发多少个信号
- // 比如说:我有100个线程,同时并发只并发5个,则设置permits为5
- // 说到这里又涉及到一个问题就是,</span><span style="color:#ff0000;">线程是越多越好么</span><span style="color:#009900;">?
- // 答案自然是否定的,这里Google官方给出的最佳并发数是当前服务器内核数+1
- // 也就是说,pertits = cpu(内核数) + 1;假如是4核的则推荐最佳并发数是5
- // 因为我的电脑是4核的,所以这里就举例并发为5,这里不再进行代码的封装,
- // 只是举一个简单的例子</span>
- //Semaphore semaphore = new Semaphore(5);// 设置并发信号量为5
- // 这里我们已经创建好并发数了,那么我们怎么使用呢?
- // 这里介绍两个核心方法,
- // 第一个:semaphore.acquire(); 获取信号或者说获取一把锁
- // 第二个:semaphore.release(); 释放信号或者说释放一把锁
- // 示例代码如下:
- for (int i = 0; i < 100; i++) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- // <span style="color:#ff0000;">注意</span>:在刚进入方法就需要获得一把锁,<span style="color:#ff0000;">再次强调,是刚进入方法就获得一把锁</span>
- try {
- semaphore.acquire();// 获取一把锁,因为是在匿名内部类中使用,所以需要将其声明为成员变量
- // 这里我想对线程进行计数,但是是多线程并发,所以不能直接用i++来计数,
- // 因此我们需要进行原子操作,为此,我们再次介绍一个工具包,“原子”,Atomic
- // 这里我们使用整形的AtomicInteger,因为需要在内部类中使用,所以声明为成员变量,设置初始化为0
- int current = atomicInteger.getAndIncrement();
- System.out.println("第" + current +"进来了");// 打印日志
- Thread.sleep(1000);// 让当前线程睡1秒,模仿耗时操作
- System.out.println("第" + current +"出去了");
- semaphore.release();// 释放一把锁,<span style="color:#ff0000;">必须释放,必须是方法最后一步</span>
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }).start();
- }
- }
- }</span>
如此,我们第一个问题就解决了,注释写的很详细,相信0基础也能看懂,代码100%运行通过,这里不再贴运行结果图片。
好,第一个问题解决了,呢么我们怎么控制使主线程等待所有子线程运行结束之后再运行呢?
这里我们需要再次介绍一工具类,示例代码如下:有详细注释
- /**
- * 注意:类很多代码在上面已经书写过详细注释,这里写过的注释不再书写
- * @author xiyang
- *
- */
- public class ThreadWaitTest {
- private static Semaphore semaphore = new Semaphore(5);// 设置并发信号量为5
- private static AtomicInteger atomicInteger = new AtomicInteger(0);// 声明原子操作整数,初始化为9
- // 这句代码详细注释见主函数,另外我这里为了方便直接设置参数为100,实际开发可以根据需求实例化
- private static CountDownLatch cdl = new CountDownLatch(100);
- public static void main(String[] args) throws InterruptedException {
- // 因为我们需要处理主线程等待所有子线程运行结束之后再运行,
- // 因此为了方便,科学,我们再次介绍一个线程并发工具包CountDownLatch,
- // 同样,我们需要它的一个有参构造,CountDownLatch cdl = new CountDownLatch(count);
- // 注意,这里参数,必须和线程池的最大数一致,也就是说,这里的参数必须是你线程运行的最大数
- // 比如我这里要运行100个线程,并发5个,那么,这里的count==100
- // 因为我们需要在内部类中使用,所以声明为成员变量
- for (int i = 0; i < 100; i++) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- // 注意:在刚进入方法就需要获得一把锁,再次强调,是刚进入方法就获得一把锁
- try {
- semaphore.acquire();// 获取一把锁,因为是在匿名内部类中使用,所以需要将其声明为成员变量
- int current = atomicInteger.getAndIncrement();
- System.out.println("第" + current +"进来了");// 打印日志
- Thread.sleep(1000);// 让当前线程睡1秒,模仿耗时操作
- System.out.println("第" + current +"出去了");
- <span style="color:#ff0000;">cdl.countDown();</span>// 此方法的意思是线程数量-1,要在当前线程执行完毕之后书写,或者说子线程核心代码执行完毕之后
- semaphore.release();// 释放一把锁,必须释放,必须是方法最后一步
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }).start();
- }
- <span style="color:#ff0000;">cdl.await();</span>// 主线程等待,当线程数量为0时主线程执行
- System.out.println("主线程执行");
- // 如此就解决了线程并发问题和主线程等待所有子线程运行完毕之后运行
- }
- }
如此以上两个需求就解决了,这里只是示例,大家可以根据具体需求具体操作,最好是可以进行封装调用,最好
相关推荐
### Java多线程--让主线程等待所有子线程执行完毕 #### 核心知识点解析 在Java多线程环境中,让主线程等待所有子线程执行完毕是一个常见的需求,尤其是在处理大量数据或进行高性能计算时。这不仅有助于正确测量...
然而,在某些情况下,我们需要等待所有子线程执行完毕后再继续执行主线程的剩余动作。这时,我们可以使用 Java 提供的 CountDownLatch 类来实现这个功能。 CountDownLatch 是一个同步辅助类,它允许一个或多个线程...
要解决“让主线程等待所有子线程执行完毕”的问题,可以采用以下策略: 1. 使用`join()`方法:如提到的,直接在每个子线程的`start()`之后调用`t.join()`,会导致所有线程按顺序执行。这是因为`join()`会让主线程...
在C#编程中,多线程是常见的并发执行方式,其中主线程通常负责应用程序的主逻辑,而子线程则可以执行一些独立的任务。当子线程完成其工作后,有时需要通知主线程以便进行下一步操作。本文将详细介绍如何在C#中实现...
JAVA 主线程等待子线程执行完毕再执行 JAVA 中的线程控制是非常重要的一部分,而在实际开发中,我们经常会遇到需要主线程等待子线程执行完毕再执行的情况。这种情况下,我们可以使用两种方式来实现:主动式和被动式...
要让主线程等待所有子线程执行完毕,但同时保持并发执行,我们可以使用一种协调机制来跟踪正在运行的子线程。上述描述中提到的方法是创建一个`ImportThread`类,它继承自`Thread`,并且维护一个`List`来存储所有正在...
有时我们可能需要设计程序,使得主线程在执行过程中能够等待所有子线程完成后再继续执行。这种需求常见于需要同步多个并行任务或者在主任务结束前确保所有子任务已经处理完毕的场景。本文将详细解释如何使用Java实现...
在Java多线程编程中,有时我们需要确保所有子线程执行完毕后再进行后续操作,例如在并发测试、数据聚合或资源清理等场景。本篇文章将详细介绍五种在Java中等待所有子线程执行完的方法。 ### 方法一:使用`sleep`...
因此,当我们遍历`thread_list`并调用`join()`时,主线程会等待所有子线程执行完毕。 在讨论中提到了一个问题:为什么在某些情况下,即使主线程结束,守护线程仍在运行?这是因为Python的交互模式下,主线程不会...
本教程重点讲解了在Python中如何处理主线程与子线程的关系,特别是主线程如何等待子线程执行完毕后再结束。 在Python中,多线程是一种并发执行的方式,可以提高程序的运行效率。`threading`模块提供了创建和管理...
在上述示例中,`join()`方法确保了主线程在子线程执行完毕后才继续运行,防止了数据竞争和资源泄漏。 其次,关于子线程返回结果到主线程的问题,我们可以利用共享变量、线程间通信或者回调函数来实现。在Java中,...
Python中的多线程是并发执行任务的重要方式,主要包括主线程和子线程。主线程是程序的入口点,而子线程是在主线程中创建的并发执行的任务单元。理解主线程与子线程的结束顺序对于编写多线程程序至关重要。 在Python...
而`join()`方法用于等待线程完成,确保主线程不会在子线程执行完毕之前继续执行。 2. **异常处理**: - 当子线程中发生异常时,`try-except`块可以用来捕获并处理这些异常。但是,`start()`方法在新栈中执行子线程...
3. 主线程等待:主线程通过调用`WaitForSingleObject()`函数进入阻塞状态,等待信号量变为可用,即子线程执行完毕。这个函数会根据返回值判断等待状态,如`WAIT_OBJECT_0`表示等待成功,`WAIT_TIMEOUT`表示超时,`...
例如,主线程调用子线程t1的join(),则主线程会等待t1执行完后再继续执行。 interrupt()方法用来中断线程。当一个线程调用wait()方法后,它会进入等待状态,需要notify()或notifyAll()唤醒。但如果调用interrupt()...
操作系统线程同步是多线程编程中的核心概念,它确保了多个并发执行的线程能够正确协调它们对共享资源的访问,避免数据竞争和死锁等问题。本实验旨在通过Windows系统环境下的实践,深入理解线程的创建、撤销以及同步...
例如,创建`test0`线程后,主线程会立即继续执行后续的`print "main 0\n"`和`print "main 1\n"`,而不会等待`test0`线程完成。只有当调用`$thr0->join`时,主线程才会暂停,等待`test0`线程结束并获取其返回值(如果...
然后调用`s.join()`,这就意味着主线程会暂停执行,直到子线程`s`执行完毕。这种行为确保了子线程的操作先于主线程的后续操作完成。 在`join()`方法的源码分析中,我们可以看到两个重载版本:一个不带参数,一个带...
最后,通过`join()`方法,主线程会等待所有线程执行完毕后再退出。这样,即使主线程结束,`f1`和`f2`依然可以在后台继续运行,直到它们各自的任务完成。 值得注意的是,`join()`方法的作用是阻塞调用线程,直到指定...