后台线程及线程工厂的方式设置一组后台线程

658 阅读3分钟

回顾上文:我们知道

  1. 定义任务类还可以通过实现Callable的方式定义,并且通过Callable定义的任务可以在任务完成时返回一定的值。
  2. 我们不能使用Thread对象去管理实现Callable的任务。需要使用Executor对象,通过调用submit()的方式去管理。
  3. submit()调用后会返回一个Future对象,它可以使用isDone()的方式去查询任务是否完成,完成后可以再调用get()的方式拿到任务的返回值。
  4. 休眠(sleep)会让任务在规定时间内终止,CPU完全让出给其他线程。让步则是发出一个信号,表示CPU可以去选择其他任务,但是有可能选的还是自己。优先级不是很推荐使用,有个印象即可。

本文内容

  1. 了解后台线程,什么是后台线程和非后台线程
  2. 了解线程工厂,做一些通用线程的配置工作

后台线程

后台线程是指程序运行过程时,在后台提供一些服务的线程。与此对应的是非后台线程。如果程序所有非后台线程结束了,就表示程序终止了,同时会杀死进程中所有的后台线程。执行的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();

image.png

ExecutorService executorService = Executors.newCachedThreadPool(new DaemonThreadFactory());
executorService.execute(new Demo());

此时executorService执行的线程都是后台线程,它在main()函数执行完毕后,也将随着程序被终止,我们都不用手动去释放线程池了...

一个注意点:设置的后台线程,如果其任务中有生成线程的语句,那其子线程也是后台线程。