Java 守护线程概述
Java的線(xiàn)程分為兩種:User Thread(用戶(hù)線(xiàn)程)、DaemonThread(守護(hù)線(xiàn)程)。
只要當(dāng)前JVM實(shí)例中尚存任何一個(gè)非守護(hù)線(xiàn)程沒(méi)有結(jié)束,守護(hù)線(xiàn)程就全部工作;只有當(dāng)最后一個(gè)非守護(hù)線(xiàn)程結(jié)束是,守護(hù)線(xiàn)程隨著JVM一同結(jié)束工作,Daemon作用是為其他線(xiàn)程提供便利服務(wù),守護(hù)線(xiàn)程最典型的應(yīng)用就是GC(垃圾回收器),他就是一個(gè)很稱(chēng)職的守護(hù)者。
User和Daemon兩者幾乎沒(méi)有區(qū)別,唯一的不同之處就在于虛擬機(jī)的離開(kāi):如果 User Thread已經(jīng)全部退出運(yùn)行了,只剩下Daemon Thread存在了,虛擬機(jī)也就退出了。 因?yàn)闆](méi)有了被守護(hù)者,Daemon也就沒(méi)有工作可做了,也就沒(méi)有繼續(xù)運(yùn)行程序的必要了。
首先看一個(gè)例子,主線(xiàn)程中建立一個(gè)守護(hù)線(xiàn)程,當(dāng)主線(xiàn)程結(jié)束時(shí),守護(hù)線(xiàn)程也跟著結(jié)束。
package com.daemon;
?
import java.util.concurrent.TimeUnit;
?
public class DaemonThreadTest
{
?? ?public static void main(String[] args)
?? ?{
?? ??? ?Thread mainThread = new Thread(new Runnable(){
?? ??? ??? ?@Override
?? ??? ??? ?public void run()
?? ??? ??? ?{
?? ??? ??? ??? ?Thread childThread = new Thread(new ClildThread());
?? ??? ??? ??? ?childThread.setDaemon(true);
?? ??? ??? ??? ?childThread.start();
?? ??? ??? ??? ?System.out.println("I'm main thread...");
?? ??? ??? ?}
?? ??? ?});
?? ??? ?mainThread.start();
?? ?}
}
?
class ClildThread implements Runnable
{
?? ?@Override
?? ?public void run()
?? ?{
?? ??? ?while(true)
?? ??? ?{
?? ??? ??? ?System.out.println("I'm child thread..");
?? ??? ??? ?try
?? ??? ??? ?{
?? ??? ??? ??? ?TimeUnit.MILLISECONDS.sleep(1000);
?? ??? ??? ?}
?? ??? ??? ?catch (InterruptedException e)
?? ??? ??? ?{
?? ??? ??? ??? ?e.printStackTrace();
?? ??? ??? ?}
?? ??? ?}
?? ?}
}
運(yùn)行結(jié)果:
I'm child thread..
I'm main thread...
如果不何止childThread為守護(hù)線(xiàn)程,當(dāng)主線(xiàn)程結(jié)束時(shí),childThread還在繼續(xù)運(yùn)行,如下:
package com.daemon;
?
import java.util.concurrent.TimeUnit;
?
public class DaemonThreadTest
{
?? ?public static void main(String[] args)
?? ?{
?? ??? ?Thread mainThread = new Thread(new Runnable(){
?? ??? ??? ?@Override
?? ??? ??? ?public void run()
?? ??? ??? ?{
?? ??? ??? ??? ?Thread childThread = new Thread(new ClildThread());
?? ??? ??? ??? ?childThread.setDaemon(false);
?? ??? ??? ??? ?childThread.start();
?? ??? ??? ??? ?System.out.println("I'm main thread...");
?? ??? ??? ?}
?? ??? ?});
?? ??? ?mainThread.start();
?? ?}
}
?
class ClildThread implements Runnable
{
?? ?@Override
?? ?public void run()
?? ?{
?? ??? ?while(true)
?? ??? ?{
?? ??? ??? ?System.out.println("I'm child thread..");
?? ??? ??? ?try
?? ??? ??? ?{
?? ??? ??? ??? ?TimeUnit.MILLISECONDS.sleep(1000);
?? ??? ??? ?}
?? ??? ??? ?catch (InterruptedException e)
?? ??? ??? ?{
?? ??? ??? ??? ?e.printStackTrace();
?? ??? ??? ?}
?? ??? ?}
?? ?}
}
運(yùn)行結(jié)果:
I'm main thread...
I'm child thread..
I'm child thread..
I'm child thread..
I'm child thread..
I'm child thread..(無(wú)限輸出)
可以看到,當(dāng)主線(xiàn)程結(jié)束時(shí),childThread是非守護(hù)線(xiàn)程,就會(huì)無(wú)限的執(zhí)行。
守護(hù)線(xiàn)程有一個(gè)應(yīng)用場(chǎng)景,就是當(dāng)主線(xiàn)程結(jié)束時(shí),結(jié)束其余的子線(xiàn)程(守護(hù)線(xiàn)程)自動(dòng)關(guān)閉,就免去了還要繼續(xù)關(guān)閉子線(xiàn)程的麻煩。不過(guò)博主推薦,如果真有這種場(chǎng)景,還是用中斷的方式實(shí)現(xiàn)比較合理。
還有補(bǔ)充一點(diǎn),不是說(shuō)當(dāng)子線(xiàn)程是守護(hù)線(xiàn)程,主線(xiàn)程結(jié)束,子線(xiàn)程就跟著結(jié)束,這里的前提條件是:當(dāng)前jvm應(yīng)用實(shí)例中沒(méi)有用戶(hù)線(xiàn)程繼續(xù)執(zhí)行,如果有其他用戶(hù)線(xiàn)程繼續(xù)執(zhí)行,那么后臺(tái)線(xiàn)程不會(huì)中斷,如下:
package com.daemon;
?
import java.util.concurrent.TimeUnit;
?
public class DaemonThreadTest
{
?? ?public static void main(String[] args)
?? ?{
?? ??? ?Thread mainThread = new Thread(new Runnable(){
?? ??? ??? ?@Override
?? ??? ??? ?public void run()
?? ??? ??? ?{
?? ??? ??? ??? ?Thread childThread = new Thread(new ClildThread());
?? ??? ??? ??? ?childThread.setDaemon(true);
?? ??? ??? ??? ?childThread.start();
?? ??? ??? ??? ?System.out.println("I'm main thread...");
?? ??? ??? ?}
?? ??? ?});
?? ??? ?mainThread.start();
?? ??? ?
?? ??? ?Thread otherThread = new Thread(new Runnable(){
?? ??? ??? ?@Override
?? ??? ??? ?public void run()
?? ??? ??? ?{
?? ??? ??? ??? ?while(true)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?System.out.println("I'm other user thread...");
?? ??? ??? ??? ??? ?try
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?TimeUnit.MILLISECONDS.sleep(1000);
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?catch (InterruptedException e)
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?e.printStackTrace();
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?});
?? ??? ?otherThread.start();
?? ?}
}
?
class ClildThread implements Runnable
{
?? ?@Override
?? ?public void run()
?? ?{
?? ??? ?while(true)
?? ??? ?{
?? ??? ??? ?System.out.println("I'm child thread..");
?? ??? ??? ?try
?? ??? ??? ?{
?? ??? ??? ??? ?TimeUnit.MILLISECONDS.sleep(1000);
?? ??? ??? ?}
?? ??? ??? ?catch (InterruptedException e)
?? ??? ??? ?{
?? ??? ??? ??? ?e.printStackTrace();
?? ??? ??? ?}
?? ??? ?}
?? ?}
}
運(yùn)行結(jié)果:
I'm other user thread...
I'm child thread..
I'm main thread...
I'm other user thread...
I'm child thread..
I'm other user thread...
I'm child thread..
I'm child thread..
I'm other user thread...
I'm other user thread...
I'm child thread..
I'm child thread..
I'm other user thread...
I'm other user thread...
I'm child thread..
I'm other user thread...
I'm child thread..
I'm other user thread...
I'm child thread..
I'm other user thread...
I'm child thread..
I'm other user thread...
I'm child thread..
I'm other user thread...
I'm child thread..
I'm other user thread...
I'm child thread..(無(wú)限輸出)
如果需要在主線(xiàn)程結(jié)束時(shí),將子線(xiàn)程結(jié)束掉,可以采用如下的中斷方式:
package com.self;
?
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
?
public class ThreadTest
{
?
?? ?public static void main(String[] args)
?? ?{
?? ??? ?Thread mainThread = new Thread(new Runnable(){
?? ??? ??? ?public void run()
?? ??? ??? ?{
?? ??? ??? ??? ?System.out.println("主線(xiàn)程開(kāi)始...");
?? ??? ??? ??? ?Thread sonThread = new Thread(new Thread1(Thread.currentThread()));
?? ??? ??? ??? ?sonThread.setDaemon(false);
?? ??? ??? ??? ?sonThread.start();
?? ??? ??? ??? ?
?? ??? ??? ??? ?try
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?TimeUnit.MILLISECONDS.sleep(10000);
?? ??? ??? ??? ?}
?? ??? ??? ??? ?catch (InterruptedException e)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?e.printStackTrace();
?? ??? ??? ??? ?}
?? ??? ??? ??? ?System.out.println("主線(xiàn)程結(jié)束");
?? ??? ??? ?}
?? ??? ?});
?? ??? ?mainThread.start();
?? ?}
?? ?
}
?
class Thread1 implements Runnable
{
?? ?private Thread mainThread;
?? ?
?? ?public Thread1(Thread mainThread)
?? ?{
?? ??? ?this.mainThread = mainThread;
?? ?}
?? ?
?? ?@Override
?? ?public void run()
?? ?{
?? ??? ?while(mainThread.isAlive())
?? ??? ?{
?? ??? ??? ?System.out.println("子線(xiàn)程運(yùn)行中....");
?? ??? ??? ?try
?? ??? ??? ?{
?? ??? ??? ??? ?TimeUnit.MILLISECONDS.sleep(1000);
?? ??? ??? ?}
?? ??? ??? ?catch (InterruptedException e)
?? ??? ??? ?{
?? ??? ??? ??? ?e.printStackTrace();
?? ??? ??? ?}
?? ??? ?}
?? ?}
?? ?
}
運(yùn)行結(jié)果:
主線(xiàn)程開(kāi)始...
子線(xiàn)程運(yùn)行中....
子線(xiàn)程運(yùn)行中....
子線(xiàn)程運(yùn)行中....
子線(xiàn)程運(yùn)行中....
子線(xiàn)程運(yùn)行中....
子線(xiàn)程運(yùn)行中....
子線(xiàn)程運(yùn)行中....
子線(xiàn)程運(yùn)行中....
子線(xiàn)程運(yùn)行中....
子線(xiàn)程運(yùn)行中....
子線(xiàn)程運(yùn)行中....
主線(xiàn)程結(jié)束
回歸正題,這里有幾點(diǎn)需要注意:
(1) thread.setDaemon(true)必須在thread.start()之前設(shè)置,否則會(huì)跑出一個(gè)IllegalThreadStateException異常。你不能把正在運(yùn)行的常規(guī)線(xiàn)程設(shè)置為守護(hù)線(xiàn)程。
(2) 在Daemon線(xiàn)程中產(chǎn)生的新線(xiàn)程也是Daemon的。?
(3) 不要認(rèn)為所有的應(yīng)用都可以分配給Daemon來(lái)進(jìn)行服務(wù),比如讀寫(xiě)操作或者計(jì)算邏輯。
寫(xiě)java多線(xiàn)程程序時(shí),一般比較喜歡用java自帶的多線(xiàn)程框架,比如ExecutorService,但是java的線(xiàn)程池會(huì)將守護(hù)線(xiàn)程轉(zhuǎn)換為用戶(hù)線(xiàn)程,所以如果要使用后臺(tái)線(xiàn)程就不能用java的線(xiàn)程池。
如下,線(xiàn)程池中將daemon線(xiàn)程轉(zhuǎn)換為用戶(hù)線(xiàn)程的程序片段:
? ? static class DefaultThreadFactory implements ThreadFactory {
? ? ? ? private static final AtomicInteger poolNumber = new AtomicInteger(1);
? ? ? ? private final ThreadGroup group;
? ? ? ? private final AtomicInteger threadNumber = new AtomicInteger(1);
? ? ? ? private final String namePrefix;
?
? ? ? ? DefaultThreadFactory() {
? ? ? ? ? ? SecurityManager s = System.getSecurityManager();
? ? ? ? ? ? group = (s != null) ? s.getThreadGroup() :
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Thread.currentThread().getThreadGroup();
? ? ? ? ? ? namePrefix = "pool-" +
? ? ? ? ? ? ? ? ? ? ? ? ? poolNumber.getAndIncrement() +
? ? ? ? ? ? ? ? ? ? ? ? ?"-thread-";
? ? ? ? }
?
? ? ? ? public Thread newThread(Runnable r) {
? ? ? ? ? ? Thread t = new Thread(group, r,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? namePrefix + threadNumber.getAndIncrement(),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0);
? ? ? ? ? ? if (t.isDaemon())
? ? ? ? ? ? ? ? t.setDaemon(false);
? ? ? ? ? ? if (t.getPriority() != Thread.NORM_PRIORITY)
? ? ? ? ? ? ? ? t.setPriority(Thread.NORM_PRIORITY);
? ? ? ? ? ? return t;
? ? ? ? }
? ? }
注意到,這里不僅會(huì)將守護(hù)線(xiàn)程轉(zhuǎn)變?yōu)橛脩?hù)線(xiàn)程,而且會(huì)把優(yōu)先級(jí)轉(zhuǎn)變?yōu)門(mén)hread.NORM_PRIORITY。
如下所示,將守護(hù)線(xiàn)程采用線(xiàn)程池的方式開(kāi)啟:
package com.daemon;
?
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
?
public class DaemonThreadTest
{
?? ?public static void main(String[] args)
?? ?{
?? ??? ?Thread mainThread = new Thread(new Runnable(){
?? ??? ??? ?@Override
?? ??? ??? ?public void run()
?? ??? ??? ?{
?? ??? ??? ??? ?ExecutorService exec = Executors.newCachedThreadPool();
?? ??? ??? ??? ?Thread childThread = new Thread(new ClildThread());
?? ??? ??? ??? ?childThread.setDaemon(true);
?? ??? ??? ??? ?exec.execute(childThread);
?? ??? ??? ??? ?exec.shutdown();
?? ??? ??? ??? ?System.out.println("I'm main thread...");
?? ??? ??? ?}
?? ??? ?});
?? ??? ?mainThread.start();
?? ?}
}
?
class ClildThread implements Runnable
{
?? ?@Override
?? ?public void run()
?? ?{
?? ??? ?while(true)
?? ??? ?{
?? ??? ??? ?System.out.println("I'm child thread..");
?? ??? ??? ?try
?? ??? ??? ?{
?? ??? ??? ??? ?TimeUnit.MILLISECONDS.sleep(1000);
?? ??? ??? ?}
?? ??? ??? ?catch (InterruptedException e)
?? ??? ??? ?{
?? ??? ??? ??? ?e.printStackTrace();
?? ??? ??? ?}
?? ??? ?}
?? ?}
}
運(yùn)行結(jié)果:
I'm main thread...
I'm child thread..
I'm child thread..
I'm child thread..
I'm child thread..
I'm child thread..
I'm child thread..
I'm child thread..
I'm child thread..
I'm child thread..(無(wú)限輸出)
上面代碼證實(shí)了線(xiàn)程池會(huì)將守護(hù)線(xiàn)程轉(zhuǎn)變?yōu)橛脩?hù)線(xiàn)程。
---------------------?
作者:朱小廝?
來(lái)源:CSDN?
原文:https://blog.csdn.net/u013256816/article/details/50392298?
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請(qǐng)附上博文鏈接!
總結(jié)
以上是生活随笔為你收集整理的Java 守护线程概述的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python数字图像处理(17):边缘与
- 下一篇: Java 守护线程