当前位置: 首页 > 后端技术 > Java

访谈攻略31:什么是守护线程?它和用户线程有什么区别?

时间:2023-04-02 00:52:26 Java

在Java语言中,线程分为两大类:用户线程和守护线程。默认情况下,我们创建的线程或者线程池都是用户线程,所以用户线程也称为普通线程。判断一个线程是用户线程还是守护线程,可以使用Thread.isDaemon()方法来判断。如果返回结果为真,则为守护线程,否则为用户线程。我们测试下线程和线程池默认属于哪种线程类型?测试代码如下:importjava.util.concurrent.LinkedBlockingQueue;importjava.util.concurrent.ThreadPoolExecutor;importjava.util.concurrent.TimeUnit;/***线程类型:daemonthreadORuserthread*/publicclassThreadType{publicstaticvoidmain(String[]args){//创建线程Threadthread=newThread(newRunnable(){@Overridepublicvoidrun(){//...}});//创建线程池ThreadPoolExecutorthreadPool=newThreadPoolExecutor(10,10,0,TimeUnit.SECONDS,newLinkedBlockingQueue<>(100));threadPool.submit(newRunnable(){@Overridepublicvoidrun(){System.out.println("ThreadPool线程类型:"+(Thread.currentThread().isDaemon()==true?"守护线程":"用户线程"));}});System.out.println("Thread线程类型:"+(thread.isDaemon()==真的吗?“守护线程”:“用户线程”));System.out.println("主线程类型:"+(Thread.currentThread().isDaemon()==true?"守护线程":"用户线程"));}}上面程序的执行结果如下图所示:从上面的结果可以看出默认创建的线程和线程池都是用户线程和守护线程。它被称为后台线程或服务线程。守护线程为用户线程服务。当程序中的所有用户线程都执行完毕后,守护线程也随之结束。守护线程的角色就像是“服务器”,用户线程的角色就像是“客户”。当所有“客户”都走了(所有执行结束)时,“服务器”(守护线程)就没有存在的意义了,所以当一个程序中的所有用户线程都执行完后,不管守护线程是否还在工作,它会和用户线程一起结束,整个程序也会结束运行。创建守护线程,我们可以通过Thread.setDaemon(true)方法将线程设置为守护线程,比如执行如下代码:publicstaticvoidmain(String[]args){Threadthread=newThread(newRunnable(){@Overridepublicvoidrun(){//...}});//设置线程为守护线程thread.setDaemon(true);System.out.println("Thread线程类型:"+(thread.isDaemon()==true?"DaemonThread":"UserThread"));System.out.println("mainthreadtype:"+(Thread.currentThread().isDaemon()==true?"DaemonThread":"UserThread"));}上面程序的执行结果如图下图:设置线程池为守护线程将线程池设置为守护线程比较麻烦,需要将线程池中的所有线程都设置为守护线程。当需要使用线程工厂ThreadFactory进行设置时(线程池中的所有线程都是通过线程工厂创建的),其具体实现代码如下:publicstaticvoidmain(String[]args)throwsInterruptedException{//thread工厂(设置守护线程)ThreadFactorythreadFactory=newThreadFactory(){@OverridepublicThreadnewThread(Runnabler){Threadthread=newThread(r);//设置为守护线程程序thread.setDaemon(true);返回线程;}};//创建线程池ThreadPoolExecutorthreadPool=newThreadPoolExecutor(10,10,0,TimeUnit.SECONDS,newLinkedBlockingQueue<>(100),threadFactory);threadPool.submit(newRunnable(){@Overridepublicvoidrun(){System.out.println("ThreadPool线程类型:"+(Thread.currentThread().isDaemon()==true?"守护线程":"用户线程"));}});Thread.sleep(2000);}上面程序的执行结果如下图所示:守护线程VS用户线程通过前面的内容,我们明白了什么是用户线程和守护线程,它们有什么区别是什么区别?接下来我们用一个小例子来观察一下。接下来我们创建一个线程,将这个线程分别设置为用户线程和守护线程,在每个线程中执行一个for循环,总共执行10次信息打印。每次打印然后休眠100毫秒,观察程序运行结果。用户线程创建的线程默认为用户线程,所以我们不需要对该线程进行任何特殊处理,执行for循环即可(一共执行10次信息打印,每次打印后休眠100毫秒),实现代码如下:publicstaticvoidmain(String[]args)throwsInterruptedException{//创建用户线程Threadthread=newThread(newRunnable(){@Overridepublicvoidrun(){for(inti=1;i<=10;i++){//打印i消息System.out.println("i:"+i);try{//睡眠100毫秒Thread.sleep(100);}catch(InterruptedExceptione){e.printStackTrace();}}}});//启动线程thread.start();}上面程序的执行结果如下图所示:从上面的结果可以看出,程序打印完10次后,进程就会正常结束。守护线程publicstaticvoidmain(String[]args)throwsInterruptedException{//创建一个守护线程Threadthread=newThread(newRunnable(){@Overridepublicvoidrun(){for(inti=1;i<=10;i++){//打印i信息System.out.println("i:"+i);try{//休眠100毫秒Thread.sleep(100);}catch(InterruptedExceptione){e.printStackTrace();}}}});//设置为守护线程thread.setDaemon(true);//启动线程thread.start();}上面程序的执行结果如下图所示:从上面的结果可以看出,当线程设置为守护线程之后,整个程序就会不是等守护线程循环10次才关闭,而是主线程结束,守护线程没有执行一个循环就结束了。从这里我们可以看出守护线程和用户线程的区别。守护线程注意事项守护线程setDaemon(true)的设置必须放在线程的start()之前,否则程序会报错。也就是说,在运行线程之前,必须先确定线程的类型,线程运行后不??允许修改线程的类型。接下来我们来演示一下,如果在程序运行后设置线程类型会出现什么问题?演示代码如下:publicstaticvoidmain(String[]args)throwsInterruptedException{Threadthread=newThread(newRunnable(){@Overridepublicvoidrun(){for(inti=1;i<=10;i++){//打印i信息System.out.println("i:"+i+",isDaemon:"+Thread.currentThread().isDaemon());try{//休眠100毫秒Thread.sleep(100);}catch(InterruptedExceptione){e.printStackTrace();}}}});//启动线程thread.start();//设置为守护线程thread.setDaemon(true);}上面程序的执行结果如下图所示:从上面的结果可以看出,当我们在start(),不仅程序执行会报错,而且设置的守护线程也不会生效。综上所述,Java语言中的线程分为两大类:用户线程和守护线程。默认情况下,我们创建的线程或线程池都是用户线程,守护线程为用户线程服务。当一个程序中的所有用户线程都执行完毕后,该程序就会结束运行。当程序结束时,它不会关心守护线程是否在运行。由此我们可以看出,守护线程在Java系统中的权重是比较低的。这就是守护线程和用户线程的区别。判断是非在自己,名誉在别人,得失在人数。公众号:Java面试真题分析面试合集:https://gitee.com/mydb/interview