昨天已經寫了:html
若是沒看的同窗建議先去閱讀一遍哦~java
在寫文章以前通讀了一遍《Java 核心技術 卷一》的併發章節和《Java併發編程實戰》前面的部分,回顧了一下之前寫過的筆記。從今天開始進入多線程的知識點咯~數據庫
我其實也是至關於從零開始學多線程的,若是文章有錯的地方還請你們多多包含,不吝在評論區下指正呢~~編程
聲明本文使用的是JDK1.8
實現多線程從本質上都是由Thread類來進行操做的~咱們來看看Thread類一些重要的知識點。Thread這個類很大,不可能整個把它看下來,只能看一些常見的、重要的方法。c#
頂部註釋的咱們已經解析過了,若是不知道的同窗可前往:多線程三分鐘就能夠入個門了!安全
咱們在使用多線程的時候,想要查看線程名是很簡單的,調用Thread.currentThread().getName()
便可。微信
若是沒有作什麼的設置,咱們會發現線程的名字是這樣子的:主線程叫作main,其餘線程是Thread-x多線程
下面我就帶着你們來看看它是怎麼命名的:併發
nextThreadNum()
的方法實現是這樣的:ide
基於這麼一個變量-->線程初始化的數量
點進去看到init方法就能夠肯定了:
看到這裏,若是咱們想要爲線程起個名字,那也是很簡單的。Thread給咱們提供了構造方法!
下面咱們來測試一下:
public class MyThread implements Runnable { @Override public void run() { // 打印出當前線程的名字 System.out.println(Thread.currentThread().getName()); } }
測試:
public class MyThreadDemo { public static void main(String[] args) { MyThread myThread = new MyThread(); //帶參構造方法給線程起名字 Thread thread1 = new Thread(myThread, "關注公衆號Java3y"); Thread thread2 = new Thread(myThread, "qq羣:742919422"); thread1.start(); thread2.start(); // 打印當前線程的名字 System.out.println(Thread.currentThread().getName()); } }
結果:
固然了,咱們還能夠經過setName(String name)
的方法來改掉線程的名字的。咱們來看看方法實現;
檢查是否有權限修改:
至於threadStatus這個狀態屬性,貌似沒發現他會在哪裏修改:
守護線程是爲其餘線程服務的
守護線程有一個特色:
使用線程的時候要注意的地方
setDaemon(boolean on)
測試一波:
public class MyThreadDemo { public static void main(String[] args) { MyThread myThread = new MyThread(); //帶參構造方法給線程起名字 Thread thread1 = new Thread(myThread, "關注公衆號Java3y"); Thread thread2 = new Thread(myThread, "qq羣:742919422"); // 設置爲守護線程 thread2.setDaemon(true); thread1.start(); thread2.start(); System.out.println(Thread.currentThread().getName()); } }
上面的代碼運行屢次能夠出現(電腦性能足夠好的同窗可能測試不出來):線程1和主線程執行完了,咱們的守護線程就不執行了~
原理:這也就爲何咱們要在啓動以前設置守護線程了。
線程優先級高僅僅表示線程獲取的CPU時間片的概率高,但這不是一個肯定的因素!
線程的優先級是高度依賴於操做系統的,Windows和Linux就有所區別(Linux下優先級可能就被忽略了)~
能夠看到的是,Java提供的優先級默認是5,最低是1,最高是10:
實現:
setPriority0
是一個本地(navite)的方法:
private native void setPriority0(int newPriority);
在上一篇介紹的時候其實也提過了線程的線程有3個基本狀態:執行、就緒、阻塞
在Java中咱們就有了這個圖,Thread上不少的方法都是用來切換線程的狀態的,這一部分是重點!
其實上面這個圖是不夠完整的,省略掉了一些東西。後面在講解的線程狀態的時候我會從新畫一個~
下面就來說解與線程生命週期相關的方法~
調用sleep方法會進入計時等待狀態,等時間到了,進入的是就緒狀態而並不是是運行狀態!
因而乎,咱們的圖就能夠補充成這樣:
調用yield方法會先讓別的線程執行,可是不確保真正讓出
因而乎,咱們的圖就能夠補充成這樣:
調用join方法,會等待該線程執行完畢後才執行別的線程~
咱們進去看看具體的實現:
wait方法是在Object上定義的,它是native本地方法,因此就看不了了:
wait方法實際上它也是計時等待(若是帶時間參數)的一種!,因而咱們能夠補充咱們的圖:
線程中斷在以前的版本有stop方法,可是被設置過期了。如今已經沒有強制線程終止的方法了!
因爲stop方法可讓一個線程A終止掉另外一個線程B
總而言之,Stop方法太暴力了,不安全,因此被設置過期了。
咱們通常使用的是interrupt來請求終止線程~
Thread t1 = new Thread( new Runnable(){ public void run(){ // 若未發生中斷,就正常執行任務 while(!Thread.currentThread.isInterrupted()){ // 正常任務代碼…… } // 中斷的處理代碼…… doSomething(); } } ).start();
再次說明:調用interrupt()並非要真正終止掉當前線程,僅僅是設置了一箇中斷標誌。這個中斷標誌能夠給咱們用來判斷何時該幹什麼活!何時中斷由咱們本身來決定,這樣就能夠安全地終止線程了!
咱們來看看源碼是怎麼講的吧:
再來看看剛纔說拋出的異常是什麼東東吧:
因此說:interrupt方法壓根是不會對線程的狀態形成影響的,它僅僅設置一個標誌位罷了
interrupt線程中斷還有另外兩個方法(檢查該線程是否被中斷):
上面還提到了,若是阻塞線程調用了interrupt()方法,那麼會拋出異常,設置標誌位爲false,同時該線程會退出阻塞的。咱們來測試一波:
public class Main { /** * @param args */ public static void main(String[] args) { Main main = new Main(); // 建立線程並啓動 Thread t = new Thread(main.runnable); System.out.println("This is main "); t.start(); try { // 在 main線程睡個3秒鐘 Thread.sleep(3000); } catch (InterruptedException e) { System.out.println("In main"); e.printStackTrace(); } // 設置中斷 t.interrupt(); } Runnable runnable = () -> { int i = 0; try { while (i < 1000) { // 睡個半秒鐘咱們再執行 Thread.sleep(500); System.out.println(i++); } } catch (InterruptedException e) { // 判斷該阻塞線程是否還在 System.out.println(Thread.currentThread().isAlive()); // 判斷該線程的中斷標誌位狀態 System.out.println(Thread.currentThread().isInterrupted()); System.out.println("In Runnable"); e.printStackTrace(); } }; }
結果:
接下來咱們分析它的執行流程是怎麼樣的:
2018年4月18日20:32:15(哇,這個方法真的消耗了我很是長的時間).....感謝@開始de痕跡的指教~
該參考資料:
能夠發現咱們的圖是尚未補全的~後續的文章講到同步的時候會繼續使用上面的圖的。在Thread中重要的仍是那幾個能夠切換線程狀態的方法,還有理解中斷的真正含義。
使用線程會致使咱們數據不安全,甚至程序沒法運行的狀況的,這些問題都會再後面講解到的~
以前在學習操做系統的時候根據《計算機操做系統-湯小丹》這本書也作了一點點筆記,都是比較淺顯的知識點。或許對你們有幫助
參考資料:
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠 關注微信公衆號:Java3y。爲了你們方便,剛新建了一下 qq羣:742919422,你們也能夠去交流交流。謝謝支持了!但願能多介紹給其餘有須要的朋友
文章的目錄導航: