线程的join方法和countdownlatch类
线程之间的状态有5种初始、就绪、运行、阻塞、死亡,大家应该都知道,线程在由运行态到阻塞态时有一种方法join。Join的功能和CountDownLatch类似,可以让所有子线程跑完再执行主线程。下面举例子说明两个的用法
1.线程的join方法,控制执行情况,实现主线程等待子线程。
我们可以拿Dota游戏来举例,在我们玩的时候可以进行单挑(Solo),玩过的应该不陌生,游戏我们认定为主线程,自己和对方定义为子线程,自己和对方的准备也就是加入A和B队伍中,加入队伍我们认定是子线程的任务。只有当己方和对方都准备好(进入各自队伍),游戏就会自动开始(对战平台自己触发的)
publicclass ThreadJoinShow {
privateclass ASubThread implements Runnable{
private String name;
public ASubThread(String name) {
this.name = name;
}
@Override
publicvoid run() {
System.out.println(name+"======正在加入游戏===");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+"======准备好了===");
}
}
privateclass BSubThread implements Runnable{
private String name;
public BSubThread(String name) {
this.name = name;
}
@Override
publicvoid run() {
System.out.println(name+"======正在加入游戏===");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+"======准备好了===");
}
}
@Test
publicvoid testNoJoin() throws InterruptedException {
System.out.println("魔兽初始界面加载请选择阵营====start");
ASubThread asub = new ASubThread("天灾方选手A");
BSubThread bsub = new BSubThread("近卫方选手B");
Thread at = new Thread(asub);
Thread bt = new Thread(bsub);
at.start();
bt.start();
System.out.println("魔兽争霸之Dota====进度条走完===进入游戏===end");
Thread.sleep(10000);//主线程暂停10s是为了防止主线程结束子线程也会跟着结束
}
@Test
publicvoid testJoin() throws InterruptedException {
System.out.println("Join版魔兽初始界面加载请选择阵营====start");
ASubThread asub = new ASubThread("Join版===天灾方选手A");
BSubThread bsub = new BSubThread("Join版===近卫方选手B");
Thread at = new Thread(asub);
Thread bt = new Thread(bsub);
at.start();
bt.start();
try {
at.join();
bt.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Join版魔兽争霸之Dota====进度条走完===进入游戏===end");
Thread.sleep(10000);//主线程暂停10s是为了防止主线程结束子线程也会跟着结束
}
}
执行测试方法console控台打印日志分别如下:
魔兽初始界面加载请选择阵营====start
魔兽争霸之Dota====进度条走完===进入游戏===end
天灾方选手A======正在加入游戏===
近卫方选手B======正在加入游戏===
天灾方选手A======准备好了===
近卫方选手B======准备好了===
Join版魔兽初始界面加载请选择阵营====start
Join版===天灾方选手A======正在加入游戏===
Join版===近卫方选手B======正在加入游戏===
Join版===天灾方选手A======准备好了===
Join版===近卫方选手B======准备好了===
Join版魔兽争霸之Dota====进度条走完===进入游戏===end
由日志可以发现,用了join方法后,主线程会等待子线程执行完,所以正常的游戏流程应该用join版,只有大家都准备好了,才能进入游戏。
2.CountDownLatch类也可以实现上述的功能,就是等所有子任务都跑完了,主线程再往下执行。
CountDownLatch有两个方法是我们常用的:await();和countDown();await()函数用于阻塞当前线程直到CountDownLatch的计数值变为0;countDown()方法用于将当前CountDownLatch的计数值减1。举个例子,假设有个女子组合TF girls要参加中戏的艺考,三个人有表演唱歌有表演朗诵有表演舞蹈,只有都通过了,才能拿到中戏的录取通知书,代码如下: public class ThreadCountDownLatchShow {
class SingSongTask implements Runnable{
private CountDownLatch countDownLatch;
public SingSongTask(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
publicvoid run() {
try {
System.out.println("===A表演唱歌的===start");
Thread.sleep(3000);
System.out.println("===A表演唱歌的==表演结束==end");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class ReadPoetryTask implements Runnable{
private CountDownLatch countDownLatch;
public ReadPoetryTask(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
publicvoid run() {
try {
System.out.println("===B表演朗读的===start");
Thread.sleep(6000);
System.out.println("===B表演朗读的==表演结束==end");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class DanceTask implements Runnable{
private CountDownLatch countDownLatch;
public DanceTask(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
publicvoid run() {
try {
System.out.println("===C表演跳舞的===start");
Thread.sleep(5000);
System.out.println("===C表演跳舞的==表演结束==end");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Test
publicvoid testGetZhongxiNotice() throws InterruptedException {
System.out.println("===TF girls参加中戏考试===");
CountDownLatch countDownLatch = new CountDownLatch(3);
ExecutorService proctorExec = Executors.newFixedThreadPool(3);
proctorExec.execute(new SingSongTask(countDownLatch));
proctorExec.execute(new ReadPoetryTask(countDownLatch));
proctorExec.execute(new DanceTask(countDownLatch));
countDownLatch.await();
proctorExec.shutdown();
System.out.println("===TF girls参加中戏考试===考试结束===通过===发录取通知书==");
}
}
执行测试方法console控台打印日志分别如下:
===TF girls参加中戏考试===
===A表演唱歌的===start
===B表演朗读的===start
===C表演跳舞的===start
===A表演唱歌的==表演结束==end
===C表演跳舞的==表演结束==end
===B表演朗读的==表演结束==end
===TF girls参加中戏考试===考试结束===通过===发录取通知书==
相关推荐
CountDownLatch与thread.join()的区别
总结来说,CountDownLatch和CyclicBarrier都是Java并发编程中的重要工具,它们可以帮助开发者协调多线程间的同步行为。CountDownLatch更适合于一次性使用的场景,用于让一个线程等待其他线程完成特定操作,而...
join()是Thread的方法,作用是调用线程需等待该join()线程执行完成后,才能继续使用下运行。应用场景:当一个线程必须等待另一个线程执行完毕才能执行时可以使用join方法。 在上面的示例代码中,我们可以看到thread...
当我们调用一个线程的`join()`方法时,当前线程会被阻塞,直到被`join()`的线程运行完毕。这在需要按顺序执行线程或者依赖其他线程完成特定任务时非常有用。例如,在处理数据的线程A完成后,我们可能希望清理资源的...
`CountDownLatch`是Java并发包(`java.util.concurrent`)中的一个工具类,它允许一个或多个线程等待其他线程完成操作。创建一个计数器为N的`CountDownLatch`,每当一个线程完成其任务时,都会调用`countDown()`,...
本教程将通过`wait()`, `notify()`, `sleep()` 和 `join()` 这四个关键方法的示例来探讨如何在Java中实现线程同步。 首先,`wait()`, `notify()` 和 `notifyAll()` 方法是Object类的一部分,它们用于线程间通信。当...
- Java的`Thread`类提供了设置线程优先级的方法,如`setPriority()`,但优先级并不保证绝对的执行顺序,只能影响调度概率,实际执行顺序依赖于JVM和操作系统。 7. **`Thread.yield()`**: - `Thread.yield()`方法...
Executor框架简化了线程池的管理和任务调度,而Future接口则允许查询任务执行结果,CountDownLatch和CyclicBarrier则常用于线程间的同步。 对于源码分析,虽然书中可能提供的实例有限,但可以从jcip-examples-src....
- Java通过`Thread`类和`Runnable`接口支持多线程编程,提供了一种在单个进程中并发执行多个任务的方法。 2. **线程实现** - 创建线程有两种主要方式:继承`Thread`类并重写`run()`方法,或实现`Runnable`接口并...
2. wait()、notify()和notifyAll():这些方法在Object类中定义,用于线程间的通信和协作。它们必须在同步环境中使用,以避免死锁。 3. Lock接口和ReentrantLock类:Java 5引入了Lock接口,提供了比synchronized更细...
- 等待(Waiting):线程调用wait()、join()或park()方法,进入等待状态,直到其他线程唤醒。 - 完结(Terminated):run()方法执行完毕或线程被中断。 3. **线程同步** - synchronized关键字:用于修饰方法或...
Java的`java.util.concurrent.ExecutorService`和`java.util.concurrent.Executors`类提供了高级线程管理功能。它们允许开发者创建线程池,有效地管理和控制线程的生命周期,减少线程创建和销毁的开销。例如,可以...
- **Thread类**:Java中的`Thread`类是所有线程的基类,包含了启动、控制和停止线程的方法,如`start()`、`run()`和`join()`。 - **Runnable接口**:`Runnable`接口提供了另一种创建线程的方式,实现该接口的类...
线程优先级和守护线程也是Java线程中的一部分,`Thread`类提供了设置优先级的方法,高优先级的线程更有可能获得CPU执行时间。守护线程是一种特殊的线程,它不会阻止JVM的退出,除非所有的非守护线程都已结束。 书中...
线程是程序执行的最小单元,每个线程都拥有自己独立的程序计数器、虚拟机栈、本地方法栈,而共享堆内存和方法区。线程之间可以并发执行,通过线程调度器来决定哪个线程应该获得CPU执行权。 在Java中,创建线程有两...
在Java线程中,还有一些关键的概念和方法: - `sleep()`: 让当前线程暂停执行指定的毫秒数,释放CPU资源,但不会释放锁。 - `join()`: 让当前线程等待指定线程完成执行。 - `isAlive()`: 检查线程是否处于活动状态...
在Java的多线程编程中,为了有效地管理和协调并发执行的线程,Java提供了一系列的并发工具类。这些工具类极大地简化了并发编程中的同步和通信问题,使得开发者能够更安全、高效地编写多线程程序。以下是针对给定标题...
线程可以通过sleep()方法进入阻塞状态,通过join()方法让主线程等待子线程完成,通过wait()和notify()或notifyAll()方法进行线程间的同步与通信。 Java提供了多种线程控制机制,如synchronized关键字用于实现互斥...
- `wait()`, `notify()`, `notifyAll()`: 这些方法在`Object`类中,用于线程间的通信和同步。它们必须在`synchronized`代码块或方法中使用。 - `volatile`关键字:确保多线程环境下变量的可见性和有序性,防止数据...
4. **线程合并与让步**:join()方法用于合并线程,让当前线程等待指定线程结束后再继续执行。yield()方法则是让当前线程暂停,让其他同优先级的线程有机会执行。 5. **守护线程(Daemon)**:守护线程是一种特殊的...