精华内容
下载资源
问答
  • 线程环境下,我们可能会需要等待开辟的线程执行完后,再去执行某个方法,例如输出并行计算结果等。 但是在线程下,线程的执行是不阻塞主线程的,这点其实也是线程的优势,提高代码执行效率,不必相互等待...

    在多线程环境下,我们可能会需要等待开辟的线程执行完后,再去执行某个方法,例如输出并行计算结果等。

    但是在多线程下,线程的执行是不阻塞主线程的,这点其实也是多线程的优势,提高代码执行效率,不必相互等待可以并行执行

    例如如下代码:

       private void button1_Click(object sender, EventArgs e)
            {
                for (int i = 0; i < 3; i++)
    	     {
                    Task task = new Task((obj) =>
                    {
                        System.Threading.Thread.Sleep(500);
                        MessageBox.Show(obj + "");
                    },i);
                    task.Start();
    	    }
    
                MessageBox.Show("线程执行完毕了");      
            }

      

      当点击按钮开启线程后,先弹出来的不是开启的线程弹窗,而是主线程的线程弹窗。

     

     现在我们来通过某些方法,实现可以在多线程执行完毕后执行自己的逻辑

    一般的处理方法有以下几种

    1:使用Task.WaitAll (会阻塞主线程)

    可以使用Task.WaitAll让主线程一直等待开辟的线程,直到所有子线程都执行完后再执行线程

    
            private void button1_Click(object sender, EventArgs e)
            {
                Task[] tasks = new Task[3];
    
                for (int i = 0; i < 3; i++)
    	    {
                    Task task = new Task((obj) =>
                    {
                        System.Threading.Thread.Sleep(500);
                        MessageBox.Show(obj + "");
                    },i);
    
                    tasks[i] = task;
                    task.Start();
    	    }
    
                Task.WaitAll(tasks);
                MessageBox.Show("线程执行完毕了");      
            }

    Task.WaitAll 是一个等待的过程,一旦全部执行完毕了,就继续往下执行,这里是阻塞的

     

     2:使用Task.WhenAll(不会阻塞主线程)

     Task.WhenAll和Task.WaitAll类似都可以做到线程执行后在向下执行,但是wait是等待也就是会阻塞主线程,而when表示当的意思,就是当子线程都执行完后在执行一个回调函数。可以把子线程执行完毕后想执行的代码放入该回调函数里边。

         private void button1_Click(object sender, EventArgs e)
            {
                Task[] tasks = new Task[3];
    
                for (int i = 0; i < 3; i++)
                {
                    Task task = new Task((obj) =>
                    {
                        System.Threading.Thread.Sleep(2000);
                        MessageBox.Show(obj + "");
                    }, i);
    
                    tasks[i] = task;
                    task.Start();
                }
    
                Task.WhenAll(tasks).ContinueWith(a =>
                {
                    MessageBox.Show("线程执行完毕了");
                });
                MessageBox.Show("主线程被执行了");
            }

     

    3:使用Parallel.Invoke或者  Parallel.For(会阻塞主线程)

    Parallel.Invoke或者  Parallel.For可以很方便的开辟多线程并行执行,自动会阻塞多线程。所以他后面写得代码会

    自动等待子线程执行完毕后再执行

       private void button2_Click(object sender, EventArgs e)
            {
                //开辟子线程,并行执行
                Parallel.Invoke(() =>
                {      
                    System.Threading.Thread.Sleep(1500);
                    MessageBox.Show("线程A");
                }, () =>
                {
     
                    System.Threading.Thread.Sleep(1500);
                    MessageBox.Show("线程B");
                });
    
                //开辟子线程,并行执行
                Parallel.For(0, 3, (a) =>
                {
                    System.Threading.Thread.Sleep(1500);
                    MessageBox.Show("线程" + a);
                });
    
                MessageBox.Show("线程执行完毕");
            }

     

    4:自己另开线程,监控线程状态(不会阻塞主线程)

    其实我们可以单独另外开辟一个新的线程了,用来监控所有子线程的运行状态,当这些被监控的线程都执行完毕后即可执行自己的逻辑,当然也可以封装一个回调函数用于方便调用。

     

    线程的状态有很多:例如Created(已经创建),Running(运行中),RanToCompletion(运行完毕)等

    我们就可以利用这些线程状态来做一些自定义操作。例如这里的等待线程执行完毕等。

    static void Main(string[] args)
            {
                Task task = new Task(() =>
                {
                    System.Threading.Thread.Sleep(2000);
                    Console.WriteLine("线程执行完了");
                });
                task.Start();
    
    
                Console.WriteLine("-------开始监听单线程执行-------");
                //一个单独的线程 监控其他线程的状态
                Task monitor_task = new Task(() =>
                {
                    while (true)
                    {
                        if (task.Status == TaskStatus.RanToCompletion) 
                        {
                            Console.WriteLine("监控到线程执行完了");
                            break;
                        }
                    }
                });
                monitor_task.Start();
    
                Console.ReadLine();
            }

     

     监控多个线程其实也是一样,监控的时候判断执行完成线程的个数就行了

      static void Main(string[] args)
            {
                Task[] tasklist = new Task[10];
    
                Dictionary<object, object> dic = new Dictionary<object, object>();
                for (int i = 0; i < 10; i++)
                {
                    Task task = new Task((a) =>
                    {
                        System.Threading.Thread.Sleep(1000);
                        dic.Add(a, a);
                    }, i);
    
                    tasklist[i] = task;
                    task.Start();
                }
    
                //用户监控其他线程的状态
                Task monitor_task = new Task(() =>
                {
                    //监控线程的个数
                    int i = 0;
                    while (true)
                    {
                        i = 0;
                        foreach (Task item in tasklist)
                        {
                            if (item.Status == TaskStatus.RanToCompletion)
                            {
                                i++;
                            }
                        }
                        if (i == 10)
                        {
                            Console.WriteLine("所有线程执行完毕" + dic.Count);
                            break;
                        }
                    }
                });
                monitor_task.Start();
                Console.ReadLine();      
            }

     

     

    展开全文
  • 主线程等待线程执行完再结束

    千次阅读 2018-09-04 16:28:00
    主线程–子线程1–子线程1的子线程1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |-子线程1的子线程2 &nbsp; ...

    主线程–子线程1–子线程1的子线程1
                |             |-子线程1的子线程2
                |
                |-子线程2

    类似这样的结构,一般来说,要保证顺序就要保证线程的种类属于:阻塞式线程。

    父级线程与子线程的阻塞性质是独立的。

    兄弟线程的阻塞是独立的。

    常见的线程阻塞方法:
    (1)命令行执行时,例如:python中,os.system(command)
    (2)线程启动后,join到主线程,那么主线程就开始阻塞。

    展开全文
  • 在我们日常的开发过程中,我们经常会开启多个线程或者创建一个线程池去执行多个并发任务,当所有任务执行完毕后,我们一般会做一个统一的处理。那我们如何直到多个线程的任务已经全部执行完毕了呢? 今天由我来为...

    一.引言:

    在我们日常的开发过程中,我们经常会开启多个线程或者创建一个线程池去执行多个并发任务,当所有任务执行完毕后,我们一般会做一个统一的处理。那我们如何知道多个线程的任务已经全部执行完毕了呢?
    今天由我来为大家介绍几种方法:

    二.join()方法

    在这里插入图片描述

            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (i<10000){
                        i++;
                    }
                }
            });
            thread1.start();
    
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (k<10000){
                        k++;
                    }
                }
            });
            thread2.start();
            
            try {
                thread1.join();
                thread2.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("i的值"+i);
            System.out.println("k的值"+k);
    

    运行程序控制台打印i和k的值都是1万,可以得出结论,线程1,线程2都执行完毕了。

    分析总结:执行join方法的线程的所在线程,一直在等待执行join方法的线程完成。如果A在B线程中执行了join()方法,那么B线程就会等待A线程执行结束。(通过while循环判断join的线程是否存活。)

    三.CountDownLatch类

    代码实现在上述代码的基础上创建一个CountDownLatch对象:
    在这里插入图片描述

           Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (i<10000){
                        i++;
                    }
                    mCountDownLatch.countDown();
                }
            });
            thread1.start();
    
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (k<10000){
                        k++;
                    }
                    mCountDownLatch.countDown();
                }
            });
            thread2.start();
    
            try {
                mCountDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("i的值"+i);
            System.out.println("k的值"+k);
    

    运行程序,控制台打印结果和上面一样。

    分析总结:CountDownLatch内部维持一个计数操作,通过CAS算法,保证操作的原子性。
    countDown()会将当前计数-1(通过Unsafe类下compareAndSwapInt方法);
    await()方法表示当前线程挂起,一直等待这个计数到0。

    四.CyclicBarrier类

    代码如下:
    在这里插入图片描述

    在这里插入图片描述

       mCyclicBarrier = new CyclicBarrier(2, mRunnable);
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (i<10000){
                        i++;
                    }
                    try {
                        mCyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            });
            thread1.start();
    
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (k<10000){
                        k++;
                    }
                    try {
                        mCyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            });
            thread2.start();
    

    执行我们应用程序,打印结果和上述结果一致。

    分析总结:
    CyclicBarrier可以理解为一个屏障。
    子线程通过调用它的await方法来告诉CyclicBarrier,线程到达屏障。当指定数量的线程
    达到屏障后,在执行线程后面的方法。打个比方我们去车站坐车,所有人到达之后,车才会发动。
    上诉代码我们通过CyclicBarrier的构造方法,指定等待2个线程到达屏障后(例如我们的车要等待多少人到齐之后才能发动)在执行后续的操作,并且指定之后都到达之后先执行什么操作(一个Runnable对象,例如我们车发动的操作)。

    四.自定义个一个计数器

    代码如下:
    在这里插入图片描述

    在这里插入图片描述

      Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (i<10000){
                        i++;
                    }
                    atomicInteger.incrementAndGet();
                    justIsOver();
                }
            });
            thread1.start();
    
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (k<10000){
                        k++;
                    }
                    atomicInteger.incrementAndGet();
                    justIsOver();
                }
            });
            thread2.start();
    

    执行我们的应用程序,控制台打印结果如上所示:

    分析总结:
    通过java提供的原子类AtomicInteger创建一个对象,用来计数。每个线程执行完毕时
    调用incrementAndGet把内部的一个计数+1,当它内部的值为2时,就代表我们的两个线程都执行完毕了。

    好了,今天我们就介绍这四种方法,还有其他方法,思想大差不差,要么设置一个同步点,要么就设置一个计数器。如果对你提供了帮助,别忘了点个赞再走哦。


    转载标明原文地址哦:https://blog.csdn.net/braintt/article/details/88381193

    展开全文
  • 这里记录一下下面这种情况:主线程需要等待多个子线程执行完后再执行。 1.使用CountDownLatch 示例如下,我们初始化一个CountDownLatch,值为10(子线程个数),然后每次一个子线程执行完后执行一下countDown()...

    这里记录一下下面这种情况:主线程需要等待多个子线程执行完后再执行。

    我们先看一下下面的场景:

    package com.java4all.mypoint;
    
    import java.util.concurrent.CountDownLatch;
    
    /**
     * Author: yunqing
     * Date: 2018/7/18
     * Description:线程测试
     * 测试点:主线程等待子线程全部执行完后再执行
     */
    public class ThreadTest {
    
        public static void main(String[] args)throws Exception{
            System.out.println("主线程正在执行前:"+Thread.currentThread().getName());
            test3();
            System.out.println("主线程正在执行后:"+Thread.currentThread().getName());
        }
    
        public static void test3(){
            try {
                for (int i = 1 ;i <= 10;i ++){
                    Thread.sleep(1000);
                    new Thread(()->{
                        System.out.println("子线程正在执行:"+Thread.currentThread().getName());
                    }).start();
                }
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }
    
    }
    
    

    执行结果为:

    主线程正在执行前:main
    子线程正在执行:Thread-0
    子线程正在执行:Thread-1
    子线程正在执行:Thread-2
    子线程正在执行:Thread-3
    子线程正在执行:Thread-4
    子线程正在执行:Thread-5
    子线程正在执行:Thread-6
    子线程正在执行:Thread-7
    子线程正在执行:Thread-8
    主线程正在执行后:main
    子线程正在执行:Thread-9
    

    可以看到,子线程还没执行完时,主线程进来了。

    1.使用CountDownLatch

    示例如下,我们初始化一个CountDownLatch,值为10(子线程个数),然后每次一个子线程执行完后执行一下countDown(),代码示例如下:

    package com.java4all.mypoint;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.TimeUnit;
    
    /**
     * Author: yunqing
     * Date: 2018/7/18
     * Description:线程测试
     * 测试点:主线程等待子线程全部执行完后再执行
     */
    public class ThreadTest {
    
        /**初始化CountDownLatch,值为线程数量*/
        private static final CountDownLatch ctl = new CountDownLatch(10);
        
        public static void main(String[] args)throws Exception{
            System.out.println("主线程正在执行前:"+Thread.currentThread().getName());
            test3();
            ctl.await(20, TimeUnit.SECONDS);//最多等待20秒,不管子线程完没完
            System.out.println("主线程正在执行后:"+Thread.currentThread().getName());
        }
    
    
        public static void test3(){
            try {
                for (int i = 1 ;i <= 10;i ++){
                    Thread.sleep(1000);
                    new Thread(()->{
                        System.out.println("子线程正在执行:"+Thread.currentThread().getName());
                    }).start();
                    ctl.countDown();
                }
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }
    
    }
    
    

    执行结果为:

    主线程正在执行前:main
    子线程正在执行:Thread-0
    子线程正在执行:Thread-1
    子线程正在执行:Thread-2
    子线程正在执行:Thread-3
    子线程正在执行:Thread-4
    子线程正在执行:Thread-5
    子线程正在执行:Thread-6
    子线程正在执行:Thread-7
    子线程正在执行:Thread-8
    子线程正在执行:Thread-9
    主线程正在执行后:main
    

    或者用java8之前的方式写:

    线程类:
    package com.java4all.mypoint;
    
    import java.util.concurrent.CountDownLatch;
    
    /**
     * Author: yunqing
     * Date: 2018/7/23
     * Description:
     */
    public class MyRunnable implements Runnable{
    
        public CountDownLatch countDownLatch;
    
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
                System.out.println("子线程正在执行任务,当前线程为:"+Thread.currentThread().getName());
            }catch (InterruptedException inex){
                inex.printStackTrace();
            }finally {
                countDownLatch.countDown();
            }
        }
    
    
        public CountDownLatch getCountDownLatch() {
            return countDownLatch;
        }
    
        public void setCountDownLatch(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }
    }
    
    
    测试类:
    package com.java4all.mypoint;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.TimeUnit;
    
    /**
     * Author: yunqing
     * Date: 2018/7/18
     * Description:线程测试
     * 测试点:主线程等待子线程全部执行完后再执行
     */
    public class ThreadTest {
    
        /**初始化CountDownLatch,值为线程数量*/
        private static final CountDownLatch ctl = new CountDownLatch(10);
    
        public static void main(String[] args)throws Exception{
            System.out.println("主线程正在执行前:"+Thread.currentThread().getName());
            for(int i = 1;i <= 10;i ++){
                MyRunnable runnable = new MyRunnable();
                runnable.setCountDownLatch(ctl);
                Thread thread = new Thread(runnable);
    
                thread.start();
            }
            ctl.await(20, TimeUnit.SECONDS);//最多等待20秒,不管子线程完没完
            System.out.println("主线程正在执行后:"+Thread.currentThread().getName());
        }
    
    }
    
    
    结果为:
    主线程正在执行前:main
    子线程正在执行任务,当前线程为:Thread-1
    子线程正在执行任务,当前线程为:Thread-0
    子线程正在执行任务,当前线程为:Thread-2
    子线程正在执行任务,当前线程为:Thread-3
    子线程正在执行任务,当前线程为:Thread-4
    子线程正在执行任务,当前线程为:Thread-7
    子线程正在执行任务,当前线程为:Thread-6
    子线程正在执行任务,当前线程为:Thread-5
    子线程正在执行任务,当前线程为:Thread-9
    子线程正在执行任务,当前线程为:Thread-8
    主线程正在执行后:main
    

    附:
    开启一个线程的其他写法:

        /**jdk7匿名内部类的写法*/
        public static void test1(){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("aaaa");
                }
            }).start();
        }
    
        /**
    	 * jdk8
    	 * Runnable是个函数接口,可以利用jdk8的lambda来简写
         * 函数接口:是指内部只有一个抽象方法的接口
         * */
        public static void test2(){
            new Thread(()->{
                System.out.println("bbb");
            }).start();
        }
    
    展开全文
  • 主线程等待多个子线程执行完才继续执行,以下是我能想到的几种方法,欢迎讨论、指正。1.闭锁CountDownLatch闭锁是典型的等待事件发生的同步工具类,将闭锁的初始值设置为与子线程数目相同,每个子线程执行完成都调用...
  • CountDownLatch 允许一个或多个线程等待其他线程完成操作。 应用场景 假如有一个列表的大量数据等待处理,最后全部处理完毕后返回处理结果。普通做法就是从头遍历,一个个顺序执行,这样单线程处理效率不高,我们...
  •   CountDownLatch:具有计数器的功能,等待其他线程执行完毕,主线程在继续执行,用于监听某些初始化操作,并且线程进行阻塞,等初始化执行完毕后,通知主线程继续工作执行。值得注意的是CountDownLatch计数的次数...
  • 前言 前段时间一直在做数据...开始设想的是,只为每张表启动一个线程,然后这一个线程直接跑所有地市。结果发现效果很差,同步一次需要大概半小时左右才能将数据同步,所以就想着改进,给每个张表分配一个主线...
  • Java主线程等待所有子线程执行完毕在执行,这个需求其实我们在工作中经常会用到,比如用户下单一个产品,后台会做一系列的处理,为了提高效率,每个处理都可以用一个线程执行,所有处理完成了之后才会返回给用户...
  • 常用的两种方式: 第一种方式:来自大神... } catch (InterruptedException E) { // handle } 然后在线程方法中加入 try { ... } catch (Exception e) { e.printStackTrace(); }finally { countDownLatch.countDown(); }
  • Springboot+多线程+等待获取执行结果

    千次阅读 2020-08-06 14:12:52
    Springboot+多线程+等待获取执行结果 在日常的开发项目过程中,时常会有多线程的使用场景。最近开发的需求中也是如此,只不过这次需要开启多线程执行,最后要等所有线程结束统一获取结果。所以在此整理一下 在...
  • Thread thread = new Thread(SendOtherData); thread.Start();
  • 问题最近我在处理一批数据,用多线程来处理,我想知道大概多久能处理。比如我先用多线程处理 100 条数据,统计下用时,然后根据总的数据量就可以大概估算出处理这批数据要多久。使用 CountDownLatch 计时思路:...
  • 问题描述 现在有一个主线程X,和两个子线程A和B,A和B之间没有依赖关系且两者的执行时间不确定,现在要求如下: ...先定义一个线程A,代码如下: public class ThreadA implements Runnable {` public void r...
  • 博主昨天去一家公司面试,被面试官问到一个问题,如果开启10个线程,但是需要这10个线程执行完成后,再交由主线程统一输入,如何实现?当时我没有回答,我对线程并不是那么的熟悉,面试结束后,我通过查阅资料...
  • java.util.concurrent.CountDownLatch ...CountDownLatch是一个同步辅助工具,用于使一个或多个线程等待(即阻塞)知道一组在其他线程中的任务结束。 CountDownLatch必须用给定的count(一个int类型的大于等于0...
  • 自己摸索这搜着些的,如果有问题,请... //同步辅助类需要通过这类来控制所有的线程执行完成; List&amp;lt;String&amp;gt; list = new ArrayList&amp;lt;&amp;gt;(); CountDownLatch countDo...
  • 多线程面试题(值得收藏)

    万次阅读 多人点赞 2019-08-16 09:41:18
    史上最强多线程面试47题(含答案),建议收藏 金九银十快到了,即将进入找工作的高峰期,最新整理的最全多线程并发面试47题和答案总结,希望对想进...可见性指多个线程操作一个共享变量时,其中一个线程对变量进行修...
  • Thread提供了一个让一个线程等待另一个线程执行完的方法——join();当线程A调用B线程join()方法后,线程A将会阻塞,只有等B线程执行完后在会执行线程A public class ThreadMain { public static void main...
  • Thread:主线程等待线程执行完毕再执行解决办法

    万次阅读 多人点赞 2019-06-20 11:20:54
    线程从启动到执行完毕,一般会有一些耗时操作,并不能像一般的程序语句,就能立马结束。如下代码: package com.xxx.async; public class WaitThreadDone { public static void main(String[] args) { Thread ...
  • 那么如果线程池嵌入在业务代码中,如何正确的等待线程池执行完,在执行后续操作呢?或者想要获取执行结果有应该怎么处理呢? 下面走一下场景: package com.example.demo1.entity; /** * create by c-pown on ...
  • Java主线程等待所有子线程执行完毕在执行,这个需求其实我们在工作中经常会用到,比如用户下单一个产品,后台会做一系列的处理,为了提高效率,每个处理都可以用一个线程执行,所有处理完成了之后才会返回给用户...
  • Java中等待线程执行完毕

    千次阅读 2017-07-18 23:10:27
    前言:前一段时间在做项目的时候,某段代码中用到了多线程,该处代码需要开启多个线程,待这几个线程执行完毕后再接着执行后续的流程。现将可采用的方法记录如下。 要达到上述的描述的情形,可以使用Thread的join()...
  • linux线程编程中,如果...如果线程A创建了三个线程B,C,D,执行完的先后顺序不知。想让A必须等待个线程都退出后再退出,应该怎么做? 连用pthread__join三次吗???但是第一次用了pthread__join后,A不就阻塞了吗?
  • PLINQ 尝试充分利用系统中的所有处理器, 它利用所有处理器的方法是,将数据源分成片段,然后在多个处理器上对单独工作线程上的每个片段并行执行查询。 在许多情况下,并行执行意味着查询运行速度显著提高。 ...
  • join的意思是使得放弃当前线程的执行,等待引用线程执行完毕。 public class MyThread implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + ...
  • Java中多个线程交替循环执行

    千次阅读 2019-05-14 10:27:17
    有些时候面试官经常会问,两个线程怎么...下面我们就来剖析一下怎么实现多个线程顺序输出。 两个线程循环交替打印 //首先我们来看一种比较简单的方式 public class ThreadCq { public static void main(Str...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 619,786
精华内容 247,914
关键字:

等待多个线程执行完