摘要:時間年月日星期六說明本文部分內容均來自慕課網。慕課網教學源碼無學習源碼第一章課前準備前言課程說明比較和這兩種線程創建的方式,需要知道和的基本創建方式。一旦主線程獲取到了用戶的輸入,這時候,阻塞就會解除掉,主線程繼續運行,直到結束。
時間:2017年07月08日星期六
說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com
教學源碼:無
學習源碼:https://github.com/zccodere/s...
課程說明
比較Thread和Runnable這兩種線程創建的方式,需要知道Thread和Runnable的基本創建方式。
課程目標和學習內容
線程創建的兩種方式比較 線程的生命周期 線程的守護神:守護線程第二章:Thread VS Runnable 2-1 回顧線程創建的兩種方式
方式一:繼承Thread類
方式二:實現Runnable接口
線程創建的兩種方式
2-2 應用Thread模擬賣票兩種方式的比較
Runnable方式可以避免Thread方式由于Java單繼承特性帶來的缺陷 Runnable的代碼可以被多個線程(Thread實例)共享,適合于多個線程處理同一個資源的情況
案例:模擬買票
代碼演示
1.編寫MyThread類
package com.myimooc.ticketsthread; /** * 使用 Thread 創建線程 * @author ZhangCheng on 2017-07-08 * */ public class MyThread extends Thread { /** 一共有5張火車票 */ 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 + "賣了1張票,剩余票數為:"+ticketsCont); } } }
2.編寫TicketsThread類
package com.myimooc.ticketsthread; /** * 主類-啟動線程類 * @author ZhangCheng on 2017-07-08 * */ public class TicketsThread { public static void main(String[] args) { // 創建三個線程,模擬三個窗口賣票 MyThread mt1 = new MyThread("窗口1"); MyThread mt2 = new MyThread("窗口2"); MyThread mt3 = new MyThread("窗口3"); // 啟動這三個線程,即窗口開始賣票 mt1.start(); mt2.start(); mt3.start(); } }
運行結果
總共有5張票,但是三個窗口加在一起賣了15張票。造成有些人買了票,上不了車,這種情況不是我們愿意看到的。具體原因,寫完Runnable后,會講解。
2-3 應用Runnable模擬賣票代碼演示
1.編寫MyThread類
package com.myimooc.ticketsrunnable; /** * 使用 Runnable 創建線程 * @author ZhangCheng on 2017-07-08 * */ public class MyThread implements Runnable { /** 一共有5張火車票 */ private int ticketsCont = 5; // 寫買票邏輯 @Override public void run() { while(ticketsCont > 0 ){ // 如果還有票,就賣掉一張 ticketsCont--; System.out.println(Thread.currentThread().getName() + "賣了1張票,剩余票數為:"+ticketsCont); } } }
2.編寫TicketsRunnable類
package com.myimooc.ticketsrunnable; /** * 主類-啟動線程類 * @author ZhangCheng on 2017-07-08 * */ public class TicketsRunnable { public static void main(String[] args) { MyThread mt = new MyThread(); // 創建三個線程,模擬三個窗口賣票 Thread th1 = new Thread(mt,"窗口1"); Thread th2 = new Thread(mt,"窗口2"); Thread th3 = new Thread(mt,"窗口3"); // 啟動這三個線程,即窗口開始賣票 th1.start(); th2.start(); th3.start(); } }
運行結果
2-4 應用揭秘兩種方式的區別
第三章:線程的生命周期和守護線程 3-1 線程的生命周期線程的生命周期
創建
新建一個線程對象,如Threaf thd = new Thread()
就緒
創建了線程對象后,調用了線程的start()方法(注意:此時線程只是進入了線程隊列,等待獲取CPU服務,具備了運行的條件,但并不一定已經開始運行了)
運行
處于就緒狀態的線程,一旦獲取了CPU資源,便進入到運行狀態,開始執行run()方法里面的邏輯
終止
線程的run()方法執行完畢,或者線程調用了stop()方法,線程便進入終止狀態
阻塞
一個正在執行的線程在某些情況下,由于某種原因而暫時讓出了CPU資源,暫停了自己的執行,便進入了阻塞狀態,如調用了sleep()方法
阻塞狀態示意圖
3-2 守護線程理論知識Java線程有兩類
用戶線程:運行在前臺,執行具體的任務 程序的主線程、連接網絡的子線程等都是用戶線程 守護線程:運行在后臺,為其他前臺線程服務 特點:一旦所有用戶線程都結束運行,守護線程會隨JVM一起結束工作 應用:數據庫連接池中的監測線程、JVM虛擬機啟動后的監測線程 最常見的守護線程:垃圾回收線程
如何設置守護線程
可以通過調用Thread類的setDaemon(true)方法來設置當前的線程為守護線程
注意事項
setDaemon(true)必須在start()方法之前調用,否則會拋出IllegalThreadStateException異常 在守護線程中產生的新線程也是守護線程 不是所有的任務都可以分配給守護線程來執行,比如讀寫操作或者計算邏輯3-3 守護線程代碼示例
模擬場景示意圖
模擬場景說明
一共有兩個線程,一個主線程,一個守護線程。守護線程會在很長的時間內不停的往文件中寫數據,主線程會阻塞等待來自鍵盤的輸入。一旦主線程獲取到了用戶的輸入,這時候,阻塞就會解除掉,主線程繼續運行,直到結束。而一旦主線程結束,用戶線程就沒有了。這時候即使數據還沒有寫完,守護線程也會隨虛擬機一起結束運行。
代碼演示
1.編寫DaemonThread類
package com.myimooc.daemonthread; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; /** * 守護線程。使用 Runnable 創建線程 * @author ZhangCheng on 2017-07-08 * */ public class DaemonThread implements Runnable { @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("d:" + File.separator + "daemon.txt"); // 向文件中追加數據 OutputStream os = new FileOutputStream(fileName,true); int count = 0; while(count < 999){ os.write((" word" + count).getBytes()); System.out.println("守護線程" + Thread.currentThread().getName() + "向文件中寫入了word" + count); count++; // 線程休眠1秒 Thread.sleep(1000); } os.close(); } }
2.編寫DaemonThreadDemo類
package com.myimooc.daemonthread; import java.util.Scanner; /** * 主線程 * @author ZhangCheng on 2017-07-08 * */ public class DaemonThreadDemo { public static void main(String[] args) { System.out.println("進入主線程" + Thread.currentThread().getName()); DaemonThread daemonThread = new DaemonThread(); Thread thread = new Thread(daemonThread); thread.setDaemon(true); thread.start(); Scanner sc = new Scanner(System.in); sc.next(); sc.close(); System.out.println("退出主線程" + Thread.currentThread().getName()); } }3-4 使用jstack生成線程快照
常用查看線程工具
jstack
作用:生成JVM當前時刻線程的快照(threaddump,即當前進程中所有線程的信息) 目的:幫助定位程序問題出現的原因,如長時間停頓、CPU占用率過高等
使用命令
jstack -l PID 生成線程快照
快照案例
2017-07-08 23:49:46 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.101-b13 mixed mode): "Thread-0" #10 daemon prio=5 os_prio=0 tid=0x000000001d209800 nid=0x2e00 waiting on condition [0x000000001dd2f000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at com.myimooc.daemonthread.DaemonThread.writeToFile(DaemonThread.java:39) at com.myimooc.daemonthread.DaemonThread.run(DaemonThread.java:19) at java.lang.Thread.run(Thread.java:745) Locked ownable synchronizers: - None "Service Thread" #9 daemon prio=9 os_prio=0 tid=0x000000001d1b9800 nid=0x2480 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "C1 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x000000001d13b000 nid=0x2078 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x000000001be2d800 nid=0x24f4 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x000000001bddf000 nid=0x2f64 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001bdde000 nid=0x1c1c waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001bdc8800 nid=0x247c runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001bdba800 nid=0x1f10 in Object.wait() [0x000000001d12f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x000000076b108ee0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143) - locked <0x000000076b108ee0> (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=0x00000000027a2800 nid=0x2214 in Object.wait() [0x000000001d02f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x000000076b106b50> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x000000076b106b50> (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=0x000000000099d800 nid=0xf2c runnable [0x000000000228e000] 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 <0x000000076b159560> (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 <0x000000076b1b9ce8> (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 com.myimooc.daemonthread.DaemonThreadDemo.main(DaemonThreadDemo.java:22) Locked ownable synchronizers: - None "VM Thread" os_prio=2 tid=0x000000001bd98000 nid=0x2998 runnable "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000026c6800 nid=0x11b0 runnable "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000026c8000 nid=0x26a4 runnable "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00000000026c9800 nid=0x2d6c runnable "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00000000026cb000 nid=0xab0 runnable "VM Periodic Task Thread" os_prio=2 tid=0x000000001d1f3000 nid=0x2b08 waiting on condition JNI global references: 6
總結
1.如果有daemon標記,則當前線程為守護線程 2.通過查看線程狀態(java.lang.Thread.State: TIMED_WAITING (sleeping)) 可以幫助我們定位到導致程序出現死鎖,或者是阻塞問題的原因 3.tid和nid字段可以幫助我們找到CPU占有率很高的線程第四章:課程總結 4-1 課程總結
課程總結
線程創建的兩種方式回顧 線程創建的兩種方式比較 線程的聲明周期 守護線程 jsrack生成線程快照
建議
多使用Runnable這種方式創建線程
補充
1.程序中的同一資源指的是同一個Runnable對象 2.安全的賣票程序中需要加入同步(Synchronized)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67333.html
時間:2017年07月09日星期日說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com教學源碼:無學習源碼:https://github.com/zccodere/s... 第一章:課程簡介 1-1 課程簡介 課程目標和學習內容 共享變量在線程間的可見性 synchronized實現可見性 volatile實現可見性 指令重排序 as-if-seria...
摘要:時間年月日星期六說明本文部分內容均來自慕課網。慕課網教學源碼學習源碼第一章課程介紹課程簡介是啥讀音是輕量級的依賴注入框架說明一個的框架需要有基礎什么是剝離注入輕量級代碼少易維護性能優異,跟比較。 時間:2017年10月14日星期六說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com 教學源碼:https://github.com/zccodere/s......
時間:2017年12月01日星期五說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com 教學源碼:無 學習源碼:https://github.com/zccodere/s... 第一章:課程介紹 1-1 課程介紹 熱部署的使用場景 本地調式 線上發布 熱部署的使用優點 無論本地還是線上,都適用 無需重啟服務器:提高開發、調式效率、提升發布、運維效率、降低運維成本 前置...
時間:2017年05月24日星期三說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com教學示例源碼:無個人學習源碼:https://github.com/zccodere/s... 第一章:課程介紹 1-1 課程介紹 什么是定時任務調度 基于給定的時間點,給定的時間間隔或者給定的執行次數自動執行的任務 在Java中的定時調度工具 Timer:小弟,能實現日常60%的定...
摘要:原文鏈接編程方法論響應式與代碼設計實戰序,來自于微信公眾號次靈均閣正文內容在一月的架構和設計趨勢報告中,響應式編程和函數式仍舊編列在第一季度的早期采納者中。 原文鏈接:《Java編程方法論:響應式RxJava與代碼設計實戰》序,來自于微信公眾號:次靈均閣 正文內容 在《2019 一月的InfoQ 架構和設計趨勢報告》1中,響應式編程(Reactive Programming)和函數式...
閱讀 1015·2021-11-22 14:56
閱讀 983·2021-11-11 16:54
閱讀 7701·2021-09-23 11:55
閱讀 3004·2021-09-22 15:57
閱讀 2792·2021-08-27 16:25
閱讀 671·2019-08-30 15:55
閱讀 1660·2019-08-30 15:43
閱讀 1595·2019-08-30 14:23