Java併發編程序列之線程狀態

併發編程序列之線程狀態

Hello,你們好,今天開始着手寫併發編程序列博客。歡迎你們訂閱點贊。談到併發編程,要談的東西可就多了,本文做爲併發編程序列的第一篇文章,結構以下:java

  1. 線程的建立方式和常見的線程API
  2. 線程的狀態
  3. 線程排查工具

1. 線程的建立方式和常見的線程API

  • 直接繼承Thread類 略。
  • 實現Runnable接口,傳入到Thread中去。略。
  • 經過Callable和Future建立線程,具備返回值:
public class CallableThreadTest implements Callable<Integer> {

    public static void main(String[] args) {
        CallableThreadTest ctt = new CallableThreadTest();
        FutureTask<Integer> ft = new FutureTask<>(ctt);
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " 的循環變量i的值" + i);
            if (i == 20) {
                new Thread(ft, "有返回值的線程").start();
            }
        }
        try {
            System.out.println("子線程的返回值:" + ft.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
    @Override
    public Integer call() throws Exception {
        int i = 0;
        for (; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
        return i;
    }
} 
複製代碼
  • 經過Executor線程池技術來啓動線程,後期講線程池時講。

而後提一下常見的線程API,說下注意點:
算法

  1. Thread的方法爲static方法,thread的方法爲實例方法。
  2. Thread方法經過實例來調用的效果是同樣同樣的,千萬不要誤解。誤覺得經過實例調用就是對某個實例的操做。
  3. Thread方法通常的語意就是對"當前代碼執行線程"!

Thread.currentThread():獲取代碼運行位置的當前線程。
thread.isAlive(); 判斷某個線程是否存活。
Thread.sleep(); 注意sleep方法是static方法,無論用實例調用,仍是類調用,效果都是同樣,讓當前執行代碼的線程sleep.
順帶說一個問題,咱們在啓動線程時,老是調用start方法,start方法的效果就是內部調用了run方法,記得必定不要本身手動調用run方法,由於若是本身調的話,那麼run方法內部的Thread類的static方法中的"當前執行線程"的含義就不是子線程了,而是調用線程。
中斷相關:
thread.interrupt();將某個線程的中斷標誌位設置爲true.注意,線程並無中斷,只是更改了標誌位。
Thread.interrupted():判斷當前線程是否中斷,執行完後,將標誌位更改成false,因此連續調用兩次,返回值有可能不同。 thread.isInterrupted();判斷該對象是不是中斷的,不改變標誌位。
廢棄方法,不要使用:
thread.suspend();
thread.resume();
thread.stop();
編程

2. 線程的狀態

Java線程狀態圖

線程狀態 描述
NEW 初始狀態,剛建立出來尚未start
RUNNABLE 運行中或者就緒狀態.
BLOCKED 阻塞狀態。注意只有synchronized關鍵字的鎖纔會到BLOCKED狀態,JUC的Lock相關的鎖是不會到這個狀態的。而是進入到WAITING或者TIMED_WAITING狀態。由於Lock接口的相關類內部都是使用LockSupport相關的方法
WAITING/TIMED_WAITING 等待狀態。
TERMINATED 線程結束

3. 線程排查工具

先說一個概念:線程上下文切換,多線程編程最忌諱的就是線程開的特別多,而後都處於空閒狀態(WAITING),這樣CPU每次切換過去都又切換走,上下文切換比較頻繁,至關耗時。 查看上下文切換頻率:
vmstat 1 多線程

通常來講1000可能是比較正常的。能夠考慮使用JUC的Automic包的Cas算法,減小上下文切換。

Jstack使用: 併發

稍微說下,先jstack生成線程dump文件。而後看下有多少線程分別處於什麼狀態。我這裏的都還算正常的。若是有不正常的。打開dump文件好好看看哪裏報的問題。
grep java.lang.Thread.State /opt/dump01 | awk '{print $2$3$4$5}' | sort |uniq -c

死鎖就更有意思了,當看到BLOCKED比較多時,並且長時間不消下去。那麼就要仔細看dump文件了,搜索BLOCKED關鍵字,而後看是哪裏報的BLOCKED,看代碼,檢查代碼的死鎖。須要注意的是,若是是使用JUC的Lock形成的死鎖,那麼久要檢查WAITING狀態下的代碼了
其次Jstack -l pid 能夠打印出鎖相關的信息。系統也能夠自動幫咱們偵測死鎖。相似於Found 1 deadlock這樣的關鍵字。
死鎖最有效的避免方法就是使用tryLock(time)了,拿不到鎖就返回。不要拿了。ide

結語

好了,打完收工。
下期預告:
線程間通信,synchronized關鍵字,volatile關鍵字.工具

相關文章
相關標籤/搜索