什么是后台线程?
"后台线程是指程序运行时在后台提供一种通用服务的线程,且这种线程不属于程序中不可或缺的一部分"。
后台线程也称为守护线程 (比如JVM处理垃圾回收 使用的就是后台线程), 我们创建的线程一般用于处理我们自己的某些任务,而后台线程主要用于一些公共的任务以提供服务。
我们创建的线程可以在start()启动前使用 thread.setDaemon(true); 来将其设置为后台线程,使用isDaemon()来判断线程是否为后台线程。
什么是非后台线程?
这句有点废话了,其实除了后台线程外其他线程都属于非后台线程,比如main函数启动运行时创建的线程。
后台线程和非后台线程还有一个区别在于, 非后台线程全部结束时表示此时程序运行结束,那么后台线程将会被全部终止。 如果非后台线程还在运行,那么那些后台线程也不会被终止。 再拿垃圾回收机制来讲,如果程序都结束了,那么JVM的垃圾回收的线程一定也会终止。
简单的案例:
在此案例中,main函数创建了十个线程,并将这些线程设置为后台线程setDaemon(true),这十个后台线程将会在run()中睡眠150毫秒然后打印出当前线程的信息,而main将会在创建完线程后睡眠175毫秒,因此这些后台线程虽然睡眠了150毫秒,但时间仍足够打印出信息。
import java.util.concurrent.TimeUnit;
/**
*
* @author Administrator
*
* main是一个非后台线程,main结束运行后(即非后台线程结束后),将会结束所有后台线程,终止程序运行
*
* 反过来讲,只要任何非后台线程还在运行,程序将不会结束
*
*/
public class test {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
Thread daemon = new Thread(new MyThread());
daemon.setDaemon(true);//设置为后台线程
daemon.start();
}
System.out.println("Thread create end!");
TimeUnit.MILLISECONDS.sleep(175);//main线程将会在175毫秒后结束,如果有线程在这时间内没有打印出信息,那么也将会被终止
}
}
class MyThread implements Runnable{
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(150);//后台线程睡眠150毫秒
System.out.println(Thread.currentThread()+" : " + this);//打印信息
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
打印出的信息:
Thread create end!
Thread[Thread-9,5,main] : com.yangsw.test1.MyThread@43cdad4b
Thread[Thread-6,5,main] : com.yangsw.test1.MyThread@5e70125b
Thread[Thread-2,5,main] : com.yangsw.test1.MyThread@5b152f18
Thread[Thread-0,5,main] : com.yangsw.test1.MyThread@9f34d54
Thread[Thread-4,5,main] : com.yangsw.test1.MyThread@33bbe97
Thread[Thread-8,5,main] : com.yangsw.test1.MyThread@35af3a51
Thread[Thread-5,5,main] : com.yangsw.test1.MyThread@12ceba90
Thread[Thread-1,5,main] : com.yangsw.test1.MyThread@627d1747
Thread[Thread-3,5,main] : com.yangsw.test1.MyThread@1f5f791b
Thread[Thread-7,5,main] : com.yangsw.test1.MyThread@70e25c99
但是,如果我们将这些后台线程的睡眠时间,从150增加到大于175 (比如180或者200), 那么那些后台线程的信息将不会被打印出来,因为main线程在175毫秒睡眠后结束了运行,此时唯一的非后台线程运行结束,整个程序也将结束,无论后台线程此时在做什么都将会被终止。
将run()中后台线程的时间修改后:
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(180);//后台线程睡眠180毫秒
System.out.println(Thread.currentThread()+" : " + this);//打印信息
} catch (InterruptedException e) {
e.printStackTrace();
}
}
打印出的信息:
Thread create end!
此时后台线程的信息都不能打印出来,因为在他们睡眠的180毫秒时间里,main已经苏醒并结束了程序运行。
我们还可以把后台线程的睡眠时间设置为和main相同的175,这样打印信息时你会发现,有部分线程的信息会被打印出来,因为在很短的时间内,部分后台线程在和main同时苏醒后打印出了信息,但是更多的后台线程来不及打印就已经被终止。
非后台线程案例:
如果在以上代码中,我们不将创建的线程设置为后台线程,以用户线程(也就是非后台线程)的身份进行信息打印的任务,那么无论怎样,信息一定会被打印出来, 虽然main线程已经结束了,但是用户创建的线程身份也为非后台线程,所以将会继续执行,打印出信息,而这些线程打印完毕后结束,此时已经没有非后台线程在运行了,程序最终终止。
修改后的代码:
代码修改后,main将会创建3个线程,但并没有把他们设置为后台线程,main线程在创建完用户线程后将直接结束,而那些每个用户线程将会在run中循环5次,每次睡眠1秒然后打印信息。
import java.util.concurrent.TimeUnit;
public class test {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 3; i++) {
Thread daemon = new Thread(new MyThread());
// daemon.setDaemon(true);//设置为后台线程
daemon.start();
}
System.out.println("Thread create end!");
// TimeUnit.MILLISECONDS.sleep(175);//main线程将会在175毫秒后结束,如果有线程在这时间内没有打印出信息,那么也将会被终止
}
}
class MyThread implements Runnable{
int i = 0;
@Override
public void run() {
try {
while(i<5) {
TimeUnit.MILLISECONDS.sleep(1000);//后台线程睡眠1000毫秒
System.out.println(Thread.currentThread()+" : " + this);//打印信息
i++;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
打印出的信息:
Thread create end!
Thread[Thread-2,5,main] : com.yangsw.test1.MyThread@627d1747
Thread[Thread-1,5,main] : com.yangsw.test1.MyThread@9f34d54
Thread[Thread-0,5,main] : com.yangsw.test1.MyThread@6e1ecd8e
Thread[Thread-0,5,main] : com.yangsw.test1.MyThread@6e1ecd8e
Thread[Thread-1,5,main] : com.yangsw.test1.MyThread@9f34d54
Thread[Thread-2,5,main] : com.yangsw.test1.MyThread@627d1747
Thread[Thread-1,5,main] : com.yangsw.test1.MyThread@9f34d54
Thread[Thread-0,5,main] : com.yangsw.test1.MyThread@6e1ecd8e
Thread[Thread-2,5,main] : com.yangsw.test1.MyThread@627d1747
Thread[Thread-0,5,main] : com.yangsw.test1.MyThread@6e1ecd8e
Thread[Thread-2,5,main] : com.yangsw.test1.MyThread@627d1747
Thread[Thread-1,5,main] : com.yangsw.test1.MyThread@9f34d54
Thread[Thread-0,5,main] : com.yangsw.test1.MyThread@6e1ecd8e
Thread[Thread-2,5,main] : com.yangsw.test1.MyThread@627d1747
Thread[Thread-1,5,main] : com.yangsw.test1.MyThread@9f34d54
因为用户线程也都是非后台线程, 只要非后台线程还在运行,程序将不会终止