在Java中有两类线程:
用户线程 (User Thread) 和 守护线程 (Daemon Thread)。
守护线程
是指在程序运行的时候在后台提供一种通用服务的线程,并不属于程序中不可或缺的部分
当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程
用户线程和守护线程区别:
唯一的不同之处就在于虚拟机的离开:如果用户线程已经全部退出运行了,只剩下守护线程存在了,虚拟机也就退出了。 因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了。
将线程转换为守护线程
通过调用Thread对象的setDaemon(true)方法来实现。在使用守护线程时需要注意一下几点:
必须在start()方法之前设置
thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。
在Daemon线程中产生的新线程也是Daemon的
守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断
编写实例
- 编写DeamonThread类实现往文件中写入数据的功能
- 在主线程中将DeamonThread设置为守护线程 并且使用键盘输入模拟阻塞状态
- 当从键盘输入后从阻塞状态进入运行状态 主线程执行结束 守护线程也结束
DeamonThread :
package thread.demo3;
import java.io.*;
/**
* 守护线程DeamonThread
* Created by heqianqian on 2017/4/15.
*/
public class DeamonThread implements Runnable {
private int count = 0;
@Override
public void run() {
System.out.println("Deamon Thread Running....");
File file = new File("Base/file/deamon/file.txt");
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file, true);
while (count < 999) {
outputStream.write(("word:"+count+"\r\n").getBytes());
System.out.println(Thread.currentThread().getName()+" write word "+count++);
Thread.sleep(1000);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (outputStream!=null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("Deamon Thread Over!");
}
}
Main:
package thread.demo3;
import java.util.Scanner;
/**
* Main
* Created by heqianqian on 2017/4/15.
*/
public class Main {
public static void main(String[] args) {
System.out.println("Main Thread Running....");
DeamonThread deamonThread = new DeamonThread();
Thread thread = new Thread(deamonThread);
thread.setDaemon(true);//设置为守护线程 且必须在start前调用
thread.start();
Scanner scanner = new Scanner(System.in);
scanner.next();//模拟阻塞
System.out.println("Main Thread Over!");
}
}
运行结果:
file.txt文件内容:
使用jstack生成线程快照
运行程序后 打开任务管理器 找到当前程序的PID
打开CMD 输入
jstack -l pid
可以看到快照结果
我们可以分析一下
C:\Users\heqianqian>jstack -l 10092
2017-04-15 09:54:03
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.92-b14 mixed mode):
"RMI RenewClean-[localhost:52353]" #18 daemon prio=5 os_prio=0 tid=0x00000000173ac000 nid=0x239c in Object.wait() [0x0000000017b0f000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x00000000d01df4c0> (a java.lang.ref.ReferenceQueue$Lock)
at sun.rmi.transport.DGCClient$EndpointEntry$RenewCleanThread.run(DGCClient.java:553)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"RMI Scheduler(0)" #17 daemon prio=5 os_prio=0 tid=0x00000000173a9000 nid=0x255c waiting on condition [0x0000000017a0e000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000d02c2350> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"GC Daemon" #14 daemon prio=2 os_prio=-2 tid=0x000000001648b800 nid=0x2428 in Object.wait() [0x0000000016f0e000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at sun.misc.GC$Daemon.run(GC.java:117)
- locked <0x00000000d02c2510> (a sun.misc.GC$LatencyLock)
Locked ownable synchronizers:
- None
"RMI Reaper" #13 prio=5 os_prio=0 tid=0x0000000016607000 nid=0x2268 in Object.wait() [0x0000000016e0f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d01dfac0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x00000000d01dfac0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
at sun.rmi.transport.ObjectTable$Reaper.run(ObjectTable.java:351)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"RMI TCP Accept-0" #12 daemon prio=5 os_prio=0 tid=0x000000001655e000 nid=0x24a0 runnable [0x0000000016d0e000]
java.lang.Thread.State: RUNNABLE
at java.net.DualStackPlainSocketImpl.accept0(Native Method)
at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
- locked <0x00000000d01df1b0> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:545)
at java.net.ServerSocket.accept(ServerSocket.java:513)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:400)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:372)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"RMI TCP Accept-34855" #11 daemon prio=5 os_prio=0 tid=0x0000000016243800 nid=0x2338 runnable [0x0000000016c0f000]
java.lang.Thread.State: RUNNABLE
at java.net.DualStackPlainSocketImpl.accept0(Native Method)
at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
- locked <0x00000000d0211318> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:545)
at java.net.ServerSocket.accept(ServerSocket.java:513)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:400)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:372)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x0000000016296000 nid=0x284c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C1 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x000000001621b000 nid=0x27c0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x0000000016215800 nid=0x286c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x0000000014c8d000 nid=0x26f0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000014c8b800 nid=0x27a0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x0000000014c40000 nid=0x2780 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000002ebd000 nid=0x279c in Object.wait() [0x0000000015faf000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x00000000d02c32b0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
Locked ownable synchronizers:
- None
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000002eb2000 nid=0x26e0 in Object.wait() [0x0000000015eaf000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000000d02ea1c8> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
Locked ownable synchronizers:
- None
"main" #1 prio=5 os_prio=0 tid=0x0000000002dc2800 nid=0x2844 in Object.wait() [0x00000000029ff000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at com.intellij.execution.rmi.RemoteServer.start(RemoteServer.java:86)
- locked <0x00000000d02c3350> (a java.lang.Object)
at org.jetbrains.idea.maven.server.RemoteMavenServer.main(RemoteMavenServer.java:22)
Locked ownable synchronizers:
- None
"VM Thread" os_prio=2 tid=0x0000000014bf7000 nid=0x2794 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002dd8800 nid=0x2878 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002dda000 nid=0x2804 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000000002ddb800 nid=0x1d9c runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000000002ddd000 nid=0x25e8 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x00000000162dc000 nid=0x27c4 waiting on condition
JNI global references: 236
C:\Users\heqianqian>
- Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.92-b14 mixed mode)
线程块运行在java虚拟机hotspot上 是64位的服务端 - 接下来是一些java自带的守护进程
比如GC线程
可以看到是deamon线程 优先级是2 当前状态为有时间的等待状态
Locked ownable synchronizers 是否处于同步块中
最后显示的是我们的主线程
可以看到主线程并不是一个守护线程 并且处于等待状态 原因是我们的键盘输入阻塞了主线程
jstack使用参数
参考文章:
http://www.cnblogs.com/diyingyun/archive/2011/12/25/2300998.html