java关于等待线程结束的问题!

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java关于等待线程结束的问题!相关的知识,希望对你有一定的参考价值。

如何等待线程结束?

在这红色的下划线部分,
等待线程结束后 QueryResult sResult123 的值 才等于 线程里的 results[0]

这么怎么弄?怎么写 求代码!谢谢大神

简单地可以使用 Thread.join() 方法来等待线程结束,例如这样修改一下:

Thread t = new Thread() 
  // 同原来的 run()
;
t.start();

// 调用这个方法,会挂起当前线程直至线程t结束
t.join();

join()方法的文档是这么写的: Waits for this thread to die.


也可以用wait/notify或mutex等机制来对两个线程进行同步,稍微复杂一点,例如使用 wait/notify:

new Thread() 
  public void run() 
    // 同原来的代码,加上以下代码用于同步
    synchronized (results) 
      results.notifyAll();
    
  
.start();

// 通过以下代码挂起当前线程,等待其他线程通知
synchronized (results) 
  results.wait();

以供参考。


同 i178269245 所说,等待线程结束势必要挂起当前线程,也就没必要用线程了,也许需要重新考虑一下这种实现方式。

参考技术A 有这种需求用什么线程,线程就是做异步处理的。

java 并发多线程 : 主线程等待子线程结束的三种方式:join / CountDownLatch / CyclicBarrier

参考

多线程001 - 主线程等待子线程结束

多线程002 - 再谈CountDownLatch

多线程003 - 再谈CyclicBarrier

在主线程中启动一些子线程,等待所有子线程执行结束后,主线程再继续执行。

比如:老板分配任务,众多工人开始工作,等所有工人完成工作后,老板进行检查。

解决方法分析:

  • 主线程通过join等待所有子线程完成后,继续执行;

  • 主线程知道子线程的数量、未完成子线程数量,主线程等待所有子线程完成后,才继续执行。

一、join

直接调用Java API中关于线程的join方法等待该线程终止,可以直接实现。

package day2;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

public class JoinDemo {

    public static void main(String[] args) {
        Worker w1 = new Worker("张三");
        Worker w2 = new Worker("李四");
        Worker w3 = new Worker("王五");

        List<Worker> workers = new ArrayList<>();
        workers.add(w1);
        workers.add(w2);
        workers.add(w3);

        Boss boss = new Boss(workers);
        boss.work();

        System.out.println("main方法结束");
    }

    public static class Boss {
        private final List<Worker> workers;

        public Boss(List<Worker> workers) {
            System.out.println("老板招收工人。");
            this.workers = workers;
        }

        public void work() {
            System.out.println("老板开始安排工人工作...");
            for (Worker worker : workers) {
                System.out.println("老板安排" + worker.getWorkerName() + "的工作");
                worker.start();
            }
            System.out.println("老板安排工作结束...");
            System.out.println();
            System.out.println("老板正在等所有的工人干完活......");
            for (Worker w : workers) {
                try {
                    w.join();
                } catch (InterruptedException e) {
                    System.out.println("e = " + e.getMessage());
                }
            }
            System.out.println("工人活都干完了,老板开始检查了!");
        }
    }

    public static class Worker extends Thread {
        private final String workerName;

        public Worker(String workerName) {
            this.workerName = workerName;
        }

        @Override
        public void run() {
            System.out.println(this.workerName + "正在干活...");
            try {
                TimeUnit.SECONDS.sleep(new Random().nextInt(10));
            } catch (InterruptedException e) {
                System.out.println("e = " + e.getMessage());
            }
            System.out.println(this.workerName + "活干完了!");
        }


        public String getWorkerName() {
            return workerName;
        }
    }
}
//老板招收工人。
//老板开始安排工人工作...
//老板安排张三的工作
//老板安排李四的工作
//老板安排王五的工作
//老板安排工作结束...
//
//老板正在等所有的工人干完活......
//张三正在干活...
//李四正在干活...
//王五正在干活...
//王五活干完了!
//张三活干完了!
//李四活干完了!
//工人活都干完了,老板开始检查了!
//main方法结束

二、CountDownLatch : 倒计时锁

可以自己实现一种计数器,用于统计子线程总数、未完成线程数,当未完成线程数大约0,主线程等待;当未完成线程数等于0,主线程继续执行。

当然,既然我们现在想到这种方式,Java API的团队当然也会想到,JDK 1.5提供了CountDownLatch用于实现上述方法。

在这里插入图片描述

latch 	英 [lætʃ]    美 [lætʃ]
n. 	门闩; 插销; 碰锁; 弹簧锁;
v. 	用插销插上; 用碰锁锁上
package day2;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class CountDownLatchDemo {

    public static void main(String[] args) {
        CountDownLatch latch = new CountDownLatch(3);

        Worker w1 = new Worker(latch, "张三");
        Worker w2 = new Worker(latch, "李四");
        Worker w3 = new Worker(latch, "王五");

        List<Worker> workers = new ArrayList<Worker>();
        workers.add(w1);
        workers.add(w2);
        workers.add(w3);

        Boss boss = new Boss(workers, latch);
        boss.work();
        System.out.println("main方法结束");
    }

    static class Boss {
        private final List<Worker> workers;
        private final CountDownLatch downLatch;


        public Boss(List<Worker> workers, CountDownLatch downLatch) {
            this.workers = workers;
            this.downLatch = downLatch;
        }

        public void work() {
            System.out.println("老板开始安排工人工作...");
            for (Worker worker : workers) {
                System.out.println("老板安排" + worker.getWorkerName() + "的工作");
                worker.start();
            }
            System.out.println("老板安排工作结束...");
            System.out.println();
            System.out.println("老板正在等所有的工人干完活......");
            try {
                //latch.await(),是等待子线程结束。
                this.downLatch.await();
            } catch (InterruptedException e) {
                System.out.println("e = " + e.getMessage());
            }
            System.out.println("工人活都干完了,老板开始检查了!");
        }
    }

    static class Worker extends Thread {
        private final CountDownLatch downLatch;
        private final String workerName;


        public Worker(CountDownLatch downLatch, String workerName) {
            this.downLatch = downLatch;
            this.workerName = workerName;
        }


        public void run() {
            System.out.println(this.workerName + "正在干活...");
            try {
                TimeUnit.SECONDS.sleep(new Random().nextInt(10));
            } catch (InterruptedException e) {
                System.out.println("e = " + e.getMessage());
            }
            System.out.println(this.workerName + "活干完了!");
            //latch.countDown(),是用于在子线程执行结束后计数器减一,即未完成子线程数减一。
            this.downLatch.countDown();
        }

        public String getWorkerName() {
            return workerName;
        }
    }
}

//老板开始安排工人工作...
//老板安排张三的工作
//老板安排李四的工作
//老板安排王五的工作
//老板安排工作结束...
//
//老板正在等所有的工人干完活......
//张三正在干活...
//王五正在干活...
//李四正在干活...
//王五活干完了!
//张三活干完了!
//李四活干完了!
//工人活都干完了,老板开始检查了!
//main方法结束

三、CyclicBarrier : 循环屏障

还有一种实现,这种方式不会阻塞主线程,但是会监听所有子线程结束。此处在上述的工人老板的场景中使用的话,代码如下:

在这里插入图片描述

cyclic 	英 [ˈsaɪklɪk]    美 [ˈsaɪklɪk]
adj. 	循环的; 周期的;


barrier 	英 [ˈbæriə(r)]   美 [ˈbæriər]
n. 	屏障; 障碍物; 障碍; 阻力; 关卡; 分界线; 隔阂;
[其他] 	复数:barriers
package day2;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;


public class CyclicBarrierDemo {

    public static void main(String[] args) {
        // parties : 障碍清除之前,必须调用{@link#await}的线程数
        // barrierAction : 当障碍物清除 时要执行的命令
        CyclicBarrier barrier = new CyclicBarrier(3, new Runnable() {
            @Override
            public void run() {
                System.out.println("工人活都干完了,老板开始检查了!");
            }
        });

        Worker w1 = new Worker("张三", barrier);
        Worker w2 = new Worker("李四", barrier);
        Worker w3 = new Worker("王五", barrier);

        List<Worker> workers = new ArrayList<Worker>();
        workers.add(w1);
        workers.add(w2);
        workers.add(w3);

        Boss boss = new Boss(workers);
        boss.work();

        System.out.println("main方法结束");
    }

    public static class Boss {
        private final List<Worker> workers;

        public Boss(List<Worker> workers) {
            this.workers = workers;
        }

        public void work() {
            System.out.println("老板开始安排工人工作...");
            for (Worker worker : workers) {
                System.out.println("老板安排" + worker.getWorkerName() + "的工作");
                worker.start();
            }
            System.out.println("老板安排工作结束...");
            System.out.println();
            System.out.println("老板正在等所有的工人干完活......");
        }
    }

    public static class Worker extends Thread {
        private final String workerName;
        private final CyclicBarrier barrier;

        public Worker(String workerName, CyclicBarrier barrier) {
            this.workerName = workerName;
            this.barrier = barrier;
        }

        @Override
        public void run() {
            System.out.println(this.workerName + "正在干活...");
            try {
                TimeUnit.SECONDS.sleep(new Random().nextInt(10));
            } catch (InterruptedException e) {
                System.out.println("e = " + e.getMessage());
            }
            System.out.println(this.workerName + "活干完了!");

            try {
                barrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }

        public String getWorkerName() {
            return workerName;
        }
    }
}
//老板开始安排工人工作...
//老板安排张三的工作
//老板安排李四的工作
//老板安排王五的工作
//老板安排工作结束...
//
//老板正在等所有的工人干完活......
//main方法结束
//王五正在干活...
//张三正在干活...
//李四正在干活...
//李四活干完了!
//王五活干完了!
//张三活干完了!
//工人活都干完了,老板开始检查了!


以上是关于java关于等待线程结束的问题!的主要内容,如果未能解决你的问题,请参考以下文章

java中请问如何等待一个线程结束在运行其他的代码?

java 实现等待时间

如何实现java主线程等待子线程执行完毕之后再执行

Java Thread.join()详解--父线程等待子线程结束后再结束

windows API主线程如何等待子线程结束后再继续运行

如何实现线程互等,线程2等待线程1结束后才继续执行。(可设置标志位) 求源代码