首先咱們來看下代碼:java
這是實現Runnable接口的方式數據庫
class MyRunnable implements Runnable { private int ticketsCont = 5; @Override public void run() { while (ticketsCont > 0) { ticketsCont--; System.out.println(Thread.currentThread().getName() + "賣了1張票,剩餘的票數爲:" + ticketsCont); } } } public class TicketsRunnable { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread1 = new Thread(myRunnable, "窗口1"); Thread thread2 = new Thread(myRunnable, "窗口2"); Thread thread3 = new Thread(myRunnable, "窗口3"); thread1.start(); thread2.start(); thread3.start(); } } //運行結果: //窗口1賣了1張票,剩餘的票數爲:4 //窗口1賣了1張票,剩餘的票數爲:3 //窗口1賣了1張票,剩餘的票數爲:2 //窗口1賣了1張票,剩餘的票數爲:1 //窗口1賣了1張票,剩餘的票數爲:0
這是繼承Thread類的方式bash
class MyThread extends Thread { //火車票的總數 private int ticketsCont = 5; //線程的名字 private String name; public MyThread(String name) { this.name = name; } @Override public void run() { while (ticketsCont > 0) { ticketsCont--; System.out.println(name + "賣了一張票,剩餘的票數爲:" + ticketsCont); } } } public class TicketsThread { public static void main(String[] args) { MyThread t1 = new MyThread("窗口1"); MyThread t2 = new MyThread("窗口2"); MyThread t3 = new MyThread("窗口3"); t1.start(); t2.start(); t3.start(); } } //運行結果: //窗口1賣了一張票,剩餘的票數爲:4 //窗口1賣了一張票,剩餘的票數爲:3 //窗口1賣了一張票,剩餘的票數爲:2 //窗口1賣了一張票,剩餘的票數爲:1 //窗口1賣了一張票,剩餘的票數爲:0 //窗口3賣了一張票,剩餘的票數爲:4 //窗口3賣了一張票,剩餘的票數爲:3 //窗口3賣了一張票,剩餘的票數爲:2 //窗口3賣了一張票,剩餘的票數爲:1 //窗口3賣了一張票,剩餘的票數爲:0 //窗口2賣了一張票,剩餘的票數爲:4 //窗口2賣了一張票,剩餘的票數爲:3 //窗口2賣了一張票,剩餘的票數爲:2 //窗口2賣了一張票,剩餘的票數爲:1 //窗口2賣了一張票,剩餘的票數爲:0
運行得出結果,你就會發現兩種方式的不一樣:服務器
出現這種狀況的緣由是兩種不一樣的線程實現方式自己就決定了其是否能進行資源共享:網絡
Thread:app
一個線程只能啓動一次,經過Thread實現線程時,線程和線程所要執行的任務是捆綁在一塊兒的。
也就使得一個任務只能啓動一個線程,不一樣的線程執行的任務是不相同的,因此兩個線程之間是不能共享資源的,也不必。
固然若是必定要Thread的實現資源共享,那麼能夠在共享變量加上static關鍵字。
Runnable:jvm
一個任務能夠啓動多個線程,經過Runnable方式實現的線程,實際是開闢一個線程,將任務傳
遞進去,由此線程執行。能夠實例化多個 Thread對象,將同一任務傳遞進去,也就是一個任務能夠
啓動多個線程來執行它。這些線程執行的是同一個任務,因此他們的資源是共享。
因此說Runnable適合多個線程處理同一個資源的狀況。socket
服務,具有了運行的條件,可是並不必定已經開始運行了)。ide
Java線程有兩類this
守護線程: 運行在後臺,爲其餘的前臺線程服務
直接上代碼:
class DaemonRunnable implements Runnable { private int count; @Override public void run() { System.out.println("進入守護線程" + Thread.currentThread().getName()); try { writeToFile(); } catch (Exception e) { e.printStackTrace(); } System.out.println("退出守護線程" + Thread.currentThread().getName()); } private void writeToFile() throws Exception { File filename=new File("E:"+File.separator+"Daemon.txt"); OutputStream os = new FileOutputStream(String.valueOf(filename), true); int count = 0; while (count < 999) { os.write(("\r\n world" + count).getBytes()); System.out.println("守護線程" + Thread.currentThread().getName() + "向文件中寫入了world" + count++); Thread.sleep(1000); } } } public class DaemonDemo { public static void main(String []args){ System.out.println("進入主線程"+Thread.currentThread().getName()); DaemonRunnable daemonRunnable=new DaemonRunnable(); Thread thread= new Thread(daemonRunnable); thread.setDaemon(true);//設置爲守護線程 thread.start(); Scanner scanner=new Scanner(System.in); scanner.next(); System.out.println("退出主線程"+Thread.currentThread().getName()); } }
這時候經過的在Console中隨便輸入字符讓主線程中止。
進入主線程main 進入守護線程Thread-0 守護線程Thread-0向文件中寫入了world0 守護線程Thread-0向文件中寫入了world1 守護線程Thread-0向文件中寫入了world2 守護線程Thread-0向文件中寫入了world3 11 退出主線程main
能夠看到用戶線程中止的時候,守護線程也中止了。
setDaemon(true)
必須在start()方法以前調用,不然會拋出IllegalThreadStateException
異常jstack是一個.exe的命令行程序,在jdk安裝目錄的bin目錄下。
個人jdk是默認安裝在C盤的,因此路徑是:C:\Program Files\Java\jdk1.8.0_131\bin
。
在bin目錄下打開Terminal,輸入jstack。
C:\Program Files\Java\jdk1.8.0_131\bin>jstack Usage: jstack [-l] <pid> (to connect to running process) jstack -F [-m] [-l] <pid> (to connect to a hung process) jstack [-m] [-l] <executable> <core> (to connect to a core file) jstack [-m] [-l] [server_id@]<remote server IP or hostname> (to connect to a remote debug server) Options: -F to force a thread dump. Use when jstack <pid> does not respond (process is hung) -m to print both java and native frames (mixed mode) -l long listing. Prints additional information about locks -h or -help to print this help message
能夠看到jstack是經過pid碼來獲取線程快照信息的。
咱們能夠打開任務管理器的 -> 詳細服務,就能夠看到當前正在運行的程序的pid碼。
而後咱們啓動主線程開始運行,在Terminal中輸入:jstack -l 4528
。
4528是我當前運行的程序的pid碼,若是沒有相應的pid碼,那麼會提示拒絕訪問。
C:\Program Files\Java\jdk1.8.0_131\bin>jstack -l 804 2017-06-24 11:01:25 // 使用的Java虛擬機版本爲Oracle的HotSpot 64位服務器版本 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode): "Thread-0" #11 daemon prio=5 os_prio=0 tid=0x00000000188ca800 nid=0x2560 waiting on condition [0x000000001941f000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at Thread.demo.DaemonRunnable.writeToFile(DaemonDemo.java:32) at Thread.demo.DaemonRunnable.run(DaemonDemo.java:18) at java.lang.Thread.run(Thread.java:748) Locked ownable synchronizers: - None "Service Thread" #10 daemon prio=9 os_prio=0 tid=0x00000000187fc800 nid=0x252c runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "C1 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x00000000187cf000 nid=0x2038 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x0000000018774800 nid=0x20c8 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x0000000018771800 nid=0x2298 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x000000001876f800 nid=0x16e0 runnable [0x0000000018e1e000] java.lang.Thread.State: RUNNABLE at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:171) at java.net.SocketInputStream.read(SocketInputStream.java:141) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) - locked <0x00000000d6132b90> (a java.io.InputStreamReader) at java.io.InputStreamReader.read(InputStreamReader.java:184) at java.io.BufferedReader.fill(BufferedReader.java:161) at java.io.BufferedReader.readLine(BufferedReader.java:324) - locked <0x00000000d6132b90> (a java.io.InputStreamReader) at java.io.BufferedReader.readLine(BufferedReader.java:389) at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64) Locked ownable synchronizers: - None "Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000017418000 nid=0x1404 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000173ce800 nid=0x1b20 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000000288d800 nid=0xf64 in Object.wait() [0x000000001871f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000d5f08ec8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143) - locked <0x00000000d5f08ec8> (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=0x0000000002882000 nid=0x148c in Object.wait() [0x000000001861f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000d5f06b68> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x00000000d5f06b68> (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=0x000000000085e800 nid=0x27d4 runnable [0x000000000215e000] java.lang.Thread.State: RUNNABLE at java.io.FileInputStream.readBytes(Native Method) at java.io.FileInputStream.read(FileInputStream.java:255) at java.io.BufferedInputStream.read1(BufferedInputStream.java:284) at java.io.BufferedInputStream.read(BufferedInputStream.java:345) - locked <0x00000000d5f5a498> (a java.io.BufferedInputStream) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) - locked <0x00000000d60ada70> (a java.io.InputStreamReader) at java.io.InputStreamReader.read(InputStreamReader.java:184) at java.io.Reader.read(Reader.java:100) at java.util.Scanner.readInput(Scanner.java:804) at java.util.Scanner.next(Scanner.java:1369) at Thread.demo.DaemonDemo.main(DaemonDemo.java:45) Locked ownable synchronizers: - None "VM Thread" os_prio=2 tid=0x0000000017386800 nid=0x1f68 runnable "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000027a7800 nid=0x2a24 runnable "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000027a9000 nid=0x71c runnable "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00000000027aa800 nid=0x16bc runnable "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00000000027ac000 nid=0x1d24 runnable "VM Periodic Task Thread" os_prio=2 tid=0x000000001882e000 nid=0x1e30 waiting on condition JNI global references: 33
我就拿Thread-0這個線程的信息作解釋:
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode)
表示使用的是Oracle HotSpot64版本的JVM,爲服務器版本,客戶端版本爲Client
"Thread-0" #11 daemon prio=5 os_prio=0 tid=0x00000000188ca800 nid=0x2560 waiting on condition [0x000000001941f000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at Thread.demo.DaemonRunnable.writeToFile(DaemonDemo.java:32) at Thread.demo.DaemonRunnable.run(DaemonDemo.java:18) at java.lang.Thread.run(Thread.java:748) Locked ownable synchronizers: - None
Thread-0
表示這個線程的名字daemon
表示該線程爲守護線程prio=5
表示線程的優先級tid
和nid
也是線程的16進制信息,結合其餘指令能夠很方便的定位出cpu佔有率很高的線程java.lang.Thread.State: TIMED_WAITING (sleeping)
表示線程的狀態爲TIMED_WAITING,這是調用了sleep()方法產生的結果-l
參數的話,Locked ownable synchronizers:- None
這一段信息是不會顯示出來的,這段表示的是鎖的額外信息,None表示爲沒有。
至於其餘的線程信息的話,有興趣的人能夠去查閱相關的資料,在這裏就不去作更多的介紹。