线程联合与守护线程
线程联合
什么是线程联合
一个线程A在占有CPU资源期间,可以让其他线程调用join()和本线程联合
一个线程等待另一个线程任务结束再运行自己的任务,因为需要使用联合线程运行结果的值
join()方法
在Java多线程编程中,join()方法是Thread类中的一个方法,用于让一个线程等待另一个线程执行完毕后再继续执行。
具体来说,当一个线程调用另一个线程的join()方法时,它会被阻塞,直到另一个线程执行完毕后才继续执行。例如,假设有两个线程A和B,如果在线程A中调用了线程B的join()方法,那么线程A会被阻塞,直到线程B执行完毕后才继续执行。
下面是join()方法的一些特点:
- join()方法可以带有一个参数,表示等待的时间,如果等待时间过长,则该方法会返回。如果不带参数,则该方法会一直等待,直到被阻塞的线程执行完毕。
- join()方法会释放CPU资源,因此不会占用CPU时间片。
- join()方法可以用于协调多个线程的执行顺序,例如,可以在主线程中调用子线程的join()方法,确保子线程执行完毕后再继续执行主线程。
需要注意的是,如果多个线程之间存在循环依赖,那么使用join()方法可能会导致死锁问题。因此,在使用join()方法时,需要谨慎处理线程之间的依赖关系,避免出现死锁等问题。
总之,join()方法是Java多线程编程中非常重要的方法之一,它可以帮助我们协调多个线程的执行顺序,实现更加复杂的业务逻辑。
纸上得来终觉浅,因此举例来验证
案例
小明给小红打招呼, 小明说了hello, 在收到小红的答复后, 小明要给小红说今天很开心。
class Ming implements Runnable {
@Override
public void run() {
System.out.println("hello , xiao hong!");
// 这里使用小红线程
Thread hong = new Thread(new Hong());
hong.start();
try {
// 等待小红做出回应
hong.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("我今天很开心");
}
}
class Hong implements Runnable{
@Override
public void run(){
try {
// 收到消息用了2s
Thread.sleep(2000);
System.out.println("hello,xiao ming!!");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
守护线程
什么是守护线程
守护线程(Daemon Thread)是指在程序运行时在后台提供一种常驻的服务,它的作用是为其他线程提供支持和服务。当所有的非守护线程都结束时,守护线程也会随之结束。
为什么需要守护线程
Java程序入口就是由JVM启动main
线程,main
线程又可以启动其他线程。当所有线程都运行结束时,JVM退出,进程结束。
如果有一个线程没有退出,JVM进程就不会退出。所以,必须保证所有线程都能及时结束。
但是有一种线程的目的就是无限循环,例如,一个定时触发任务的线程。
但是有了这个无限循环的线程,我的JVM进程永远不会退出, 这显然不是我要的结果。
为此,我们将不会退出的线程设为守护线程, 这样,当非守护线程结束,主程序就会退出。
守护线程的特点
守护线程的特点如下:
- 守护线程是在后台运行的,它不会影响程序的主要逻辑,而只是在后台提供一些支持和服务。
- 守护线程的生命周期与程序的生命周期相同,当程序结束时,守护线程也会随之结束。
- 守护线程通常是一些比较简单的任务,如垃圾回收、日志输出等等。
案例
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Daemon());
thread.start();
}
}
class Daemon implements Runnable {
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
System.out.println(LocalDateTime.now());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
上面的例子,放进编译器运行,编译器永远不会停止。
但当我在调用start()
方法前,调用setDaemon(true)
把该线程标记为守护线程时,又会发生什么呢?
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Daemon());
// 设为守护线程
thread.setDaemon(true);
thread.start();
// 为了效果明显,使主线程休息一会儿。
Thread.sleep(2000);
}
}
class Daemon implements Runnable {
@Override
public void run() {
while (true){
try {
System.out.println(LocalDateTime.now());
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
运行两秒后,主线程结束,守护线程也随之死亡。
守护线程是独立于其它线程的,它退出只有两种情况:
- 自身任务执行完毕
- 主线程结束