併發編程系列之線程簡介

前言

前幾天我們把Java內存模型介紹了下,大家對JMM也有所認識了,從今天我們就開始走進一個我們天天掛在嘴邊,聽在耳邊的東西:線程,對於線程相信大家都不會陌生,當然也有很多小夥伴在開發中或多或少的使用到線程,即使你沒有使用過,但是並不代表你的程序中不存在,相反,他是一定會存在的,雖然這有點廢話,OK,那我們廢話也不多說,今天我們先對線程做個簡單的介紹,那麼,讓我們一起開始新的旅途吧。

什麼是線程?

線程是現代操作系統調度的最小單元,也叫輕量級進程,在一個進程中可以創建多個線程,每個線程都擁有自己單獨的計數器,堆棧和局部變量等屬性,並且能夠訪問共享的內存變量,處理器在這些線程之間,快速的切換,使用戶造成多線程併發執行的錯感,其實多線程本質上還是單線程,只是處理器在快速切換線程處理。

Java程序天生就是多線程程序,下面我們以一個main方法爲例,我們什麼都不做,只是啓動一個main方法,看看執行結果:

public static void main(String[] args) {
   // 獲取線程管理bean
   ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
   ThreadInfo[] dumpAllThreads = threadMXBean.dumpAllThreads(false, false);
   for (int i = 0; i < dumpAllThreads.length; i++) {
     System.out.println("系統中線程編號:"+dumpAllThreads[i].getThreadId()+" 線程名字:"+dumpAllThreads[i].getThreadName());
   }
 }

執行結果:
系統中線程編號:5 線程名字:Attach Listener
系統中線程編號:4 線程名字:Signal Dispatcher
系統中線程編號:3 線程名字:Finalizer
系統中線程編號:2 線程名字:Reference Handler
系統中線程編號:1 線程名字:main

從上面執行結果我們就能看到main方法在執行的時候,並不是只有一個main線程在執行,還有另外4個線程也在執行(對上面幾個線程分被代表什麼意思感興趣的小夥伴可以自己去查閱相關資料)。

爲什麼要使用多線程?

正確的使用多線程能帶來下面幾種好處

更多的處理器核心:線程是大多數操作系統調度的基本單元,一個程序運行過程中能夠創建多個線程,而一個線程在一個時刻只能運行在一個處理器核心上,假設在單線程環境下,一個線程只能使用一個處理器核心,就算有再多的處理器核心,也還是無法利用同時處理多個線程,所以這個時候多核系統的價值就無法體現出現,而多線程環境下,我們將計算邏輯分配到多個線程上,由多個處理器核心同時處理,顯著提高系統的處理效率;

更快的響應時間:我們在處理業務邏輯時,可以將數據一致性不強的操作分給其他線程異步去處理,而儘快的響應用戶請求,縮短了響應時間;

更好的編程模型:Java爲多線程編程提供了一套完整的,良好的編程模型,使開發人員更快速方面的開發有安全保障的業務程序;

線程的優先級

現代操作系統基本採用時分的形式調度運行的線程,操作系統會分出一個個時間片,線程會分配到若干時間片,當線程的時間片用完就會觸發線程調度,並等待下次分配,線程分配到的時間片多少決定了線程使用處理器資源的多少,而線程優先級就是決定線程能分配資源的多少。

在JAVA線程中,通過一個int priority來控制優先級,範圍爲1-10,其中10最高,默認值爲5,優先級越高的線程分配到的時間片的數量越多。

設置線程優先級時的2個規則:

  • 如果線程是頻繁阻塞的線程,那麼就需要設置較高的優先級,給予足夠的時間來處理該線程,防止線程阻塞導致進程崩潰;

  • 對於偏重計算(使用較多的CPU時間)的線程,要設置較低的優先級,防止處理器被獨佔;

關於優先級的相關源碼如下:

線程優先級默認分3級,1-5-10

   /**
    * The minimum priority that a thread can have.
    */
   public final static int MIN_PRIORITY = 1;

  /**
    * The default priority that is assigned to a thread.
    */
   public final static int NORM_PRIORITY = 5;

   /**
    * The maximum priority that a thread can have.
    */
   public final static int MAX_PRIORITY = 10;

設置優先級:

public final void setPriority(int newPriority) {
       ThreadGroup g;
       checkAccess();
       if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
           throw new IllegalArgumentException();
       }
       if((g = getThreadGroup()) != null) {
           if (newPriority > g.getMaxPriority()) {
               newPriority = g.getMaxPriority();
           }
           setPriority0(priority = newPriority);
       }
   }

線程的狀態

線程在運行的生命週期中有6種狀態,如下:

public enum State {
       // 初始狀態,線程被創建,但是還沒有調用start方法
       NEW,
       // 運行狀態(運行中和就緒都屬於運行狀態)
       RUNNABLE,
       // 阻塞狀態,鎖導致的阻塞
       BLOCKED,
       // 等待狀態,當前線程需要等待其他線程動作
       WAITING,
       // 超時等待狀態,可以在指定時間內自行返回
       TIMED_WAITING,
       // 終止狀態,表示線程執行完畢
       TERMINATED;
   }

線程各個狀態之間的轉換過程如下圖:

守護線程(Daemon)

守護線程是一種支持性線程,因爲它主要被用作程序中後臺調度以及支持性工作,也就是說,當Java虛擬機中不存在非守護線程時,虛擬機就會執行退出。

使用如下方法將普通線程設置成守護線程:

Thread thread = new Thread();    
   thread.setDaemon(true);

源碼如下:

public final void setDaemon(boolean on) {
       checkAccess();
       if (isAlive()) {
           throw new IllegalThreadStateException();
       }
       daemon = on;
   }

 

以上就是今天我們對線程的簡介,通過本篇文章,讓我們對線程有個概念和認識,方便我們後面內容的展開,感謝閱讀,感謝關注!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章