java后台线程_Java多线程——<五>后台线程(daemon)

本文深入探讨了Java中守护线程的概念及其应用场景,包括定义、创建方法、与非守护线程的区别,以及如何通过自定义线程工厂来创建守护线程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、后台线程(守护线程)

学一个东西,最重要的一点就是,为什么要用它?

后台线程区别于普通线程,普通线程又可以称为用户线程,只完成用户自己想要完成的任务,不提供公共服务。而有时,我们希望编写一段程序,能够提供公共的服务,保证所有用户针对该线程的请求都能有响应。

仔细来看下后台线程的定义:指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。

二、实现后台线程

1.我们先定义任务及响应的线程

定义任务:Thread.yield();让线程暂停一段时间

class DaemonSpawn implementsRunnable{public voidrun(){while(true)

Thread.yield();

}

}

定一个线程,有一个属性Thread[] t,用于存放子线程

class Daemon implementsRunnable{//该任务下创建很多子线程

private Thread[] t = new Thread[10];public voidrun(){//为线程池填充线程,并将所有线程启动

for(int i = 0 ; i < t.length ; i++){

t[i]= new Thread(newDaemonSpawn());

t[i].start();

System.out.println("DaemonSpawn "+i+"started, ");

}for(int i = 0 ; i < t.length ; i++){

System.out.println("t["+i+"].isDaemon()="+t[i].isDaemon()+", ");

}/** Daemon进入了无线循环,并在循环里调用yield方法把控制权交给其他进程*/

while(true)

Thread.yield();

}

}

讲定义的线程设定为后台线程

public static void main(String[] args) throwsInterruptedException{/** Daemon被设置为了后台线程,它的所有子线程也自然就是后台线程了*/Thread d= new Thread(newDaemon());

d.setDaemon(true);

d.start();

System.out.println("d.isDaemon()="+d.isDaemon()+",");

TimeUnit.SECONDS.sleep(1);

}

至此,后台线程已定义并跑起来了。输出结果:

DaemonSpawn 0started,

DaemonSpawn 1started,

DaemonSpawn 2started,

DaemonSpawn 3started,

DaemonSpawn 4started,

DaemonSpawn 5started,

DaemonSpawn 6started,

DaemonSpawn 7started,

DaemonSpawn 8started,

DaemonSpawn 9started,

t[0].isDaemon()=true,

t[1].isDaemon()=true,

t[2].isDaemon()=true,

t[3].isDaemon()=true,

t[4].isDaemon()=true,

t[5].isDaemon()=true,

t[6].isDaemon()=true,

t[7].isDaemon()=true,

t[8].isDaemon()=true,

t[9].isDaemon()=true,

d.isDaemon()+true,

2.有一点要指出:所有的“非后台线程”结束时,程序也就终止了,同时会杀死进程中所有后台线程:main就是一个非后台线程

首先,如何证明main是非后台线程,还是用是上面那段程序

2484eebdc99518b8894908efb2fb9e27.png

其次,如何证明非后台线程退出后,后台线程会被杀死呢?

public class TaskDaemon implementsRunnable{

@Overridepublic voidrun() {try{while(true){

TimeUnit.MILLISECONDS.sleep(100);

System.out.println(Thread.currentThread()+" "+this);

}

}catch(InterruptedException e){

System.out.println("sleep() interrupted");

}

}public static void main(String[] args) throwsInterruptedException{/** 可以通过查看该程序的结果理解后台线程

* 创建了9个线程,都声明为后台线程,然后启动他们,在非后台线程结束之前,后台线程会被线程调用器调用

* main就是一个非后台线程,for循环结束之后输出了"All daemons started"证明main快要结束了,但是你让它睡眠了一会保证main不退出

* 这样后台线程就会跑着,于是有了后面的打印结果*/

for(int i = 0 ; i < 10 ; i++){//后台线程本质上也是一个线程,通过任务来创建该线程

Thread daemon = new Thread(newTaskDaemon());//想将创建的线程声明为后台线程 ,必须在启动前将其设置为true

daemon.setDaemon(true);

daemon.start();

}

System.out.println("All daemons started");

TimeUnit.MILLISECONDS.sleep(175);

}

}

3.通过isDaemon()方法来判断一个线程是否是一个后台线程

一个后台线程创建的任何线程都将被自动设置成后台线程,例如:Daemons中所示。

4.后台线程在不执行finally字句的情况下就会终止其run()方法,例如:DaemonsDontRunFinally

class ADaemon implementsRunnable{

@Overridepublic voidrun() {try{

System.out.println("Starting ADaemon");

TimeUnit.SECONDS.sleep(1);

}catch(InterruptedException e){

System.out.println("Exiting via InterruptedException");

}finally{

System.out.println("Thie should always run?");

}

}

}

public static voidmain(String[] args){//当最后一个非后台线程终止时,后台线程会“突然”终止//故一旦main退出,jvm就会立即关闭所有的后台进程,而不会有任何你希望出现的确认形式

Thread t = new Thread(newADaemon());//如果注释掉下面这句话,finally将会执行

t.setDaemon(true);

t.start();

}

可以看到输出结果,finally中结果并没有执行

三、自定义后台线程工厂

1.自定义后台线程工厂

public class TaskDaemonFactory implementsThreadFactory{publicThread newThread(Runnable r){

Thread t= newThread(r);

t.setDaemon(true);returnt;

}

}

2.创建线程时试用该工厂

/** Executors.newCachedThreadPool();方法用来接受一个ThreadFactory对象,而这个对象将被用来创建新的线程

* 所以,你的Facotry重写了ThreadFacotry方法之后,要去实现他的创建线程方法,方法里默认将线程声明为后台线程*/ExecutorService exec= Executors.newCachedThreadPool(newTaskDaemonFactory());for(int i = 0 ;i < 10 ;i++){

exec.execute(newTaskDaemonFromFactory());//这个是一个自定义任务

}

System.out.println("All daemons started");

TimeUnit.MILLISECONDS.sleep(500);

四、总结

后台线程(daemon)

|——定义:指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分

|       |——所有的“非后台线程”结束时,程序也就终止了,同时会杀死进程中所有后台线程:main就是一个非后台线程

|——声明并试用后台线程

|       |——传统方式:通过声明线程,操作线程来定义后台线程

|       |         |——Thread daemon = new Thread(new TaskDaemon());//将任务交给线程也叫声明线程

|       |         |——daemon.setDaemon(true);//将线程设置为后台线程

|       |         |——daemon.start();//启动后台线程

|       |——由executor调用线程工厂:通过编写定制的ThreadFactory,可以定制由Executor创建的线程的属性

|           |——1.实现ThreadFactory接口

|           |——2.重写newThread方法

|           |——public Thread newThread(Runnable r){

|           |——Thread t = new Thread(r);

|           |——t.setDaemon(true);

|           |——return t;

|           |——}

|           |——3.将定制的TaskDaemonFactory传递给Executor,它将用此来生成对应的线程,并操纵他们

|           |——每个静态的ExecutorService创建方法都被重载为接受一个ThreadFactory对象,该对象将被用来创建新的线程

|           |——ExecutorService exec = Executors.newCachedThreadPool(new TaskDaemonFactory());

|           |——4.将任务传递给exec,它会帮你执行线程操作

|           |——exec.execute(new TaskDaemonFromFactory());

注:以上代码均来自《Thinking in java》,总结内容均是个人理解,如有错误请大家批评指正,谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值