用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。
CountDownLatch 是一个通用同步工具,它有很多用途。将计数 1 初始化的 CountDownLatch 用作一个简单的开/关锁存器,或入口:在通过调用 countDown() 的线程打开入口前,所有调用 await 的线程都一直在入口处等待。用 N 初始化的 CountDownLatch 可以使一个线程在 N 个线程完成某项操作之前一直等待,或者使其在某项操作完成 N 次之前一直等待。
CountDownLatch 的一个有用特性是,它不要求调用 countDown 方法的线程等到计数到达零时才继续,而在所有线程都能通过之前,它只是阻止任何线程继续通过一个 await。
示例用法: 下面给出了两个类,其中一组 worker 线程使用了两个倒计数锁存器:
第一个类是一个启动信号,在 driver 为继续执行 worker 做好准备之前,它会阻止所有的 worker 继续执行。
第二个类是一个完成信号,它允许 driver 在完成所有 worker 之前一直等待。
class Driver { // ...
void main() throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
for (int i = 0; i < N; ++i) // create and start threads
new Thread(new Worker(startSignal, doneSignal)).start();
doSomethingElse(); // don't let run yet
startSignal.countDown(); // let all threads proceed
doSomethingElse();
doneSignal.await(); // wait for all to finish
}
}
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}
另一种典型用法是,将一个问题分成 N 个部分,用执行每个部分并让锁存器倒计数的 Runnable 来描述每个部分,然后将所有 Runnable 加入到 Executor 队列。当所有的子部分完成后,协调线程就能够通过 await。(当线程必须用这种方法反复倒计数时,可改为使用 CyclicBarrier。)
class Driver2 { // ...
void main() throws InterruptedException {
CountDownLatch doneSignal = new CountDownLatch(N);
Executor e = ...
for (int i = 0; i < N; ++i) // create and start threads
e.execute(new WorkerRunnable(doneSignal, i));
doneSignal.await(); // wait for all to finish
}
}
class WorkerRunnable implements Runnable {
private final CountDownLatch doneSignal;
private final int i;
WorkerRunnable(CountDownLatch doneSignal, int i) {
this.doneSignal = doneSignal;
this.i = i;
}
public void run() {
try {
doWork(i);
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}
public class WaitAllSubThread {
/*int liveThreadNum;//记录运行的子线程数
*/
int n; //工作线程数
public WaitAllSubThread(int n) {
this.n = n;
}
class Worker implements Runnable {
String name;
int sleep;
public Worker(String name, int sleep) {
this.name = name;
this.sleep = sleep;
}
public void run() {
/*upLive(); //计算此线程已经工作.
*/
System.out.println(name+", start to work.");
try {
Thread.sleep(sleep); //虚拟工作. 10s 随机时间
} catch (InterruptedException e) {
System.out.println(name+" interrupted.");
}
System.out.println(name+", end to work ["+sleep+"] sleep.");
/*downLive(); //此线程工作完成
*/
}
}
/* //记录线程数的同步方法.
private synchronized void downLive() {
liveThreadNum--;
}
private synchronized void upLive() {
liveThreadNum++;
}
private synchronized boolean isLive() {
return liveThreadNum > 0;
}*/
public void run() {
System.out.println("-------------main run start-------------");
int sleepSaid = 10 * 1000; //每个工作线程虚拟工作最大时间
Random rm = new Random();
for(int i=0; i<ths.length; i++) {
ths[i] = new Thread(new MyTask(rm.nextInt(sleep)+1));
ths[i].start();
}
for(Thread th : ths) {
try {
th.join();//join方式
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*//等待所有工作线程完成.
while(isLive()) {
try {
Thread.sleep(1000); //每隔1s查看下是否所有线程完成.
} catch (InterruptedException e) {
System.out.println("main thread sleep interrupted.");
}
}*/
System.out.println("---------------main run end--------------");
}
public static void main(String[] args) {
WaitAllSubThread wast = new WaitAllSubThread(10);
wast.run();
}
}
public class CountDownLatchUse {
final CountDownLatch downLatch;
int n; //工作线程数
public CountDownLatchUse(int n) {
this.downLatch = new CountDownLatch(n);
this.n = n;
}
class Worker implements Runnable {
String name;
int sleep;
public Worker(String name, int sleep) {
this.name = name;
this.sleep = sleep;
}
public void run() {
System.out.println(name+", start to work.");
try {
Thread.sleep(sleep); //虚拟工作. 10s 随机时间
} catch (InterruptedException e) {
System.out.println(name+" interrupted.");
}
System.out.println(name+", end to work ["+sleep+"] sleep.");
meDone(); //某个工作线程完成
}
}
private void meDone() {
downLatch.countDown();
}
public void run() {
System.out.println("-------------main run start-------------");
int sleepSaid = 10 * 1000; //每个工作线程虚拟工作最大时间
Random rm = new Random();
for(int i=0; i<n; i++) {
new Thread(new Worker("worker-"+i, rm.nextInt(sleepSaid)+1)).start();
}
try {
downLatch.await(); //等待所有工作线程完成.
} catch (InterruptedException e) {
System.out.println("main interrupted.");
}
System.out.println("---------------main run end--------------");
}
public static void main(String[] args) {
CountDownLatchUse mtu = new CountDownLatchUse(10);
mtu.run();
}
}
分享到:
相关推荐
总的来说,Java提供了丰富的多线程同步机制,可以根据实际需求选择合适的方法来实现“主线程等待所有子线程完成再继续”的功能。在并发编程中,理解并灵活运用这些工具对于提高程序效率和避免死锁等问题至关重要。
尝试在每个子线程的开始使用`t.join()`方法,虽然可以强制主线程等待子线程的完成,但这会导致线程顺序执行,失去并行处理的优势,违背了使用多线程的目的。 **3. 自定义线程类实现并发控制** 为了解决上述问题,...
要解决“让主线程等待所有子线程执行完毕”的问题,可以采用以下策略: 1. 使用`join()`方法:如提到的,直接在每个子线程的`start()`之后调用`t.join()`,会导致所有线程按顺序执行。这是因为`join()`会让主线程...
`Thread.join()`方法允许主线程等待特定线程结束。例如,如果有多个子线程,我们可以在每个子线程执行`join()`,这样主线程会依次等待每个子线程完成。例如: ```java Thread thread1 = new Thread(...); Thread ...
通过使用主线程的join()方法,可以让主线程等待其他线程的执行完成后继续执行。 三、使用线程的wait方法 wait()是Object的方法,作用是让当前线程等待其他线程的唤醒。应用场景:当一个线程需要等待其他线程的结果...
CountDownLatch与thread.join()的区别
在`ThreadDemo06.java`和`ThreadDemo08.java`中,可能会使用`join()`来确保主线程或其他线程在执行后续操作前等待特定线程结束。例如,如果有一个计算密集型的子线程,主程序可能需要等待它完成后再进行输出或处理...
`Semaphore`信号量控制对有限资源的访问,`CountDownLatch`计数器用于等待一组线程完成操作,`CyclicBarrier`循环栅栏允许一组线程等待彼此到达某个点后再继续执行,而`Phaser`是Java 7引入的更高级的同步工具。...
`join()`方法确保主线程等待所有子线程执行完毕后再继续。 在实际的多线程编程中,我们还需要考虑线程安全问题,避免数据竞争和死锁。此外,线程优先级、线程池等也是提高系统性能的重要手段。对于更复杂的场景,还...
线程可以通过sleep()方法进入阻塞状态,通过join()方法让主线程等待子线程完成,通过wait()和notify()或notifyAll()方法进行线程间的同步与通信。 Java提供了多种线程控制机制,如synchronized关键字用于实现互斥...
CountDownLatch更适合于一次性使用的场景,用于让一个线程等待其他线程完成特定操作,而CyclicBarrier则适用于多轮迭代的场景,让一组线程在每轮开始前等待所有线程到达同一位置。了解并熟练运用这些工具,能有效...
- `join()`方法使主线程等待子线程结束。 - `yield()`方法让当前线程暂停,让其他线程有机会执行。 4. **线程同步** - 当多个线程访问共享资源时,需要进行同步控制,防止数据不一致。 - `synchronized`关键字...
- 等待(Waiting):线程进入等待状态,如调用`wait()`、`join()`或`park()`方法。 - 完成(Terminated):`run()`方法执行完毕或线程被中断。 3. **线程同步机制**: - `synchronized`关键字:用于锁定代码块或...
线程可以通过yield()让出当前CPU时间片,join()方法使主线程等待子线程完成,sleep()方法使线程暂停指定时间。 4. **线程同步**: - **synchronized** 关键字用于控制多线程对共享资源的访问,保证同一时刻只有一...
在处理包含图片和文字的文档时,如果图片加载是异步的(例如从云上获取),可以使用`Future`来获取图片,主线程继续解析文字。这样可以避免因等待图片加载而阻塞整个解析过程,提高程序的响应性。 了解并熟练使用...
- `join()`方法让调用的线程等待目标线程执行完毕后再继续执行。 2. **`synchronized`关键字**: - `synchronized`用于实现线程同步,防止数据的不一致性。它可以修饰方法或代码块,当一个线程进入同步块/方法后...
例如,使用`Thread.Join`方法可以让主线程等待子线程完成,`Thread.Interrupt`方法可以中断线程。 8. **死锁和活锁**:当两个或更多线程互相等待对方释放资源时,就会发生死锁。活锁则是线程不断地重试导致无法进行...
Java提供了多种控制线程的方法,如start()启动线程,run()执行线程任务,sleep()让线程暂时休眠,join()等待其他线程结束,yield()让当前线程暂停,让其他线程有机会运行,以及设置优先级等。 并发控制是多线程编程...
- 主线程会捕获子线程的未捕获异常,可以通过UncaughtExceptionHandler处理。 14. **Future和Callable接口** - Future接口表示异步计算的结果,可以检查任务是否完成,获取结果,取消任务。 - Callable接口定义...
`join()`方法允许一个线程等待另一个线程完成其执行。调用join()的线程会暂停执行,直到指定的线程运行完毕。这对于线程间的有序执行和协作很有帮助。 4. **ThreadLocal**: ThreadLocal是另一种线程安全的机制,...