回顾上文:我们知道
- 定义任务类还可以通过实现
Callable
的方式定义,并且通过Callable
定义的任务可以在任务完成时返回一定的值。- 我们不能使用
Thread
对象去管理实现Callable
的任务。需要使用Executor
对象,通过调用submit()
的方式去管理。submit()
调用后会返回一个Future
对象,它可以使用isDone()
的方式去查询任务是否完成,完成后可以再调用get()
的方式拿到任务的返回值。- 休眠(sleep)会让任务在规定时间内终止,CPU完全让出给其他线程。让步则是发出一个信号,表示CPU可以去选择其他任务,但是有可能选的还是自己。优先级不是很推荐使用,有个印象即可。
本文内容:
- 了解后台线程,什么是后台线程和非后台线程
- 了解线程工厂,做一些通用线程的配置工作
后台线程
后台线程是指程序运行过程时,在后台提供一些服务的线程。与此对应的是非后台线程。如果程序所有非后台线程结束了,就表示程序终止了,同时会杀死进程中所有的后台线程。执行的main()
函数是一个非后台线程。
通过一个例子了解一下。我们定义一个任务,里面有一个休眠,使用Thread
去管理。
static class Demo implements Runnable{
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("running");
}
}
main()
public static void main(String[] args) {
Thread thread = new Thread(new Demo());
thread.start();
}
现在这个thread
默认是一个非后台线程,只要有任何非后台线程还在运行start()
,程序就不会终止。所以尽管任务中有sleep()
,但是还是会等待该线程执行完毕后,再关闭程序。
但是我们将thread
设置成后台线程的话,程序就不会再等待其执行完成后再关闭了。
设置的方法是:thread.setDaemon(true)
需要在
start()
调用之前,将该线程指定为后台线程。
public static void main(String[] args) {
Thread thread = new Thread(new Demo());
thread.setDaemon(true);
thread.start();
}
线程工厂
显式线程Thread
通过调用setDaemon()
的方式设置后台线程,一个个指定的话比较麻烦,JDK提供了线程工厂,可以统一的为线程去指定某些属性。
比如封装了一个工具类,指定线程都是为后台线程,该工具类是实现ThreadFactory
,重写newThread
方法去返回一个定义的线程。
public class DaemonThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
return thread;
}
}
使用时,我们可以将该工具类实例化后,调用newThread
方法,将任务作为参数传递进去,就的自动得到一个设置为后台线程的线程。
除了这种直接实例化的,我们还可以将这个工具类作为参数传入到Executor.newCachedThreadPool()
;
ExecutorService executorService = Executors.newCachedThreadPool(new DaemonThreadFactory());
executorService.execute(new Demo());
此时executorService
执行的线程都是后台线程,它在main()
函数执行完毕后,也将随着程序被终止,我们都不用手动去释放线程池了...
一个注意点:设置的后台线程,如果其任务中有生成线程的语句,那其子线程也是后台线程。