在 Java 言语中,线程分为两类:用户线程和看护线程,默许情况下咱们创立的线程或线程池都是用户线程,所以用户线程也被称之为一般线程。
想要查看线程到底是用户线程仍是看护线程,能够经过 Thread.isDaemon() 办法来判断,假如回来的成果是 true 则为看护线程,反之则为用户线程。
咱们来测验一下默许情况下线程和线程池归于哪种线程类型?测验代码如下:
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 线程类型:看护线程 OR 用户线程
*/
public class ThreadType {
public static void main(String[] args) {
// 创立线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//...
}
});
// 创立线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 10,
0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100));
threadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("ThreadPool 线程类型:" +
(Thread.currentThread().isDaemon() == true ? "看护线程" : "用户线程"));
}
});
System.out.println("Thread 线程类型:" +
(thread.isDaemon() == true ? "看护线程" : "用户线程"));
System.out.println("main 线程类型:" +
(Thread.currentThread().isDaemon() == true ? "看护线程" : "用户线程"));
}
}
以上程序的履行成果如下图所示: 从上述成果能够看出,默许情况下创立的线程和线程池都是用户线程。
看护线程界说
看护线程(Daemon Thread)也被称之为后台线程或服务线程,看护线程是为用户线程服务的,当程序中的用户线程悉数履行完毕之后,看护线程也会跟从完毕。 看护线程的角色就像“服务员”,而用户线程的角色就像“顾客”,当“顾客”悉数走了之后(悉数履行完毕),那“服务员”(看护线程)也就没有了存在的含义,所以当一个程序中的悉数用户线程都完毕履行之后,那么不管看护线程是否还在作业都会随着用户线程一块完毕,整个程序也会随之完毕运转。
创立看护线程
咱们能够经过 Thread.setDaemon(true) 办法将线程设置为看护线程,比方以下代码的完结:
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//...
}
});
// 设置线程为看护线程
thread.setDaemon(true);
System.out.println("Thread 线程类型:" +
(thread.isDaemon() == true ? "看护线程" : "用户线程"));
System.out.println("main 线程类型:" +
(Thread.currentThread().isDaemon() == true ? "看护线程" : "用户线程"));
}
以上程序的履行成果如下图所示:
将线程池设置为看护线程
要把线程池设置为看护线程相对来说麻烦一些,需要将线程池中的一切线程都设置成看护线程,这个时分就需要使用线程工厂 ThreadFactory 来设置了(线程池中的一切线程都是经过线程工厂创立的),它的详细完结代码如下:
public static void main(String[] args) throws InterruptedException {
// 线程工厂(设置看护线程)
ThreadFactory threadFactory = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
// 设置为看护线程
thread.setDaemon(true);
return thread;
}
};
// 创立线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 10,
0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), threadFactory);
threadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("ThreadPool 线程类型:" +
(Thread.currentThread().isDaemon() == true ? "看护线程" : "用户线程"));
}
});
Thread.sleep(2000);
}
以上程序的履行成果如下图所示:
看护线程 VS 用户线程
经过前面的内容咱们了解了什么是用户线程和看护线程了,那二者有什么区别呢?接下来咱们用一个小示例来调查一下。 接下来咱们将创立一个线程,分别将这个线程设置为用户线程和看护线程,在每个线程中履行一个 for 循环,一共履行 10 次信息打印,每次打印之后休眠 100 毫秒,来调查程序的运转成果。
用户线程
新建的线程默许便是用户线程,因此咱们无需对线程进行任何特殊的处理,履行 for 循环即可(一共履行 10 次信息打印,每次打印之后休眠 100 毫秒),完结代码如下:
public static void main(String[] args) throws InterruptedException {
// 创立用户线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
// 打印 i 信息
System.out.println("i:" + i);
try {
// 休眠 100 毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 发动线程
thread.start();
}
以上程序的履行成果如下图所示: 从上述成果能够看出,当程序履行完 10 次打印之后才会正常完毕进程。
看护线程
public static void main(String[] args) throws InterruptedException {
// 创立看护线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
// 打印 i 信息
System.out.println("i:" + i);
try {
// 休眠 100 毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 设置为看护线程
thread.setDaemon(true);
// 发动线程
thread.start();
}
以上程序履行成果如下图所示: 从上述成果能够看出,当线程设置为看护线程之后,整个程序不会等看护线程 for 循环 10 次之后再进行封闭,而是当主线程完毕之后,看护线程一次循环都没履行就完毕了,由此能够看出看护线程和用户线程的不同。
看护线程注意事项
看护线程的设置 setDaemon(true) 必须要放在线程的 start() 之前,否则程序会报错。也便是说在运转线程之前,一定要先确定线程的类型,而且线程运转之后是不允许修正线程的类型的。 接下来咱们来演示一下,假如在程序运转履行再设置线程的类型会出现什么问题?演示代码如下:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
// 打印 i 信息
System.out.println("i:" + i + ",isDaemon:" +
Thread.currentThread().isDaemon());
try {
// 休眠 100 毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 发动线程
thread.start();
// 设置为看护线程
thread.setDaemon(true);
}
以上程序履行成果如下图所示: 从上述成果能够看出,当咱们将 setDaemon(true) 设置在 start() 之后,不但程序的履行会报错,而且设置的看护线程也不会收效。
总结
在 Java 言语中线程分为两类:用户线程和看护线程,默许情况下咱们创立的线程或线程池都是用户线程,看护线程是为用户线程服务的,当一个程序中的一切用户线程都履行完结之后程序就会完毕运转,程序完毕运转时不会管看护线程是否正在运转,由此咱们能够看出看护线程在 Java 系统中权重是比较低的,这便是看护线程和用户线程的区别。
对错审之于己,毁誉听之于人,得失安之于数。
公众号:Java面试真题解析
面试合集:gitee.com/mydb/interv…