Java併發編程的藝術讀書筆記(第四章)

第四章Java併發編程基礎

前言:之前寫了前三章的筆記,雖然寫筆記讓我的閱讀慢下來可以更仔細的反覆閱讀某些部分,但是現在重看筆記,卻覺得沒有營養,一是書上內容居多,自己的想法不多,二是內容雜亂沒有整體思路。反觀書本,對我來說直觀的感受是,這不是一本適合基礎的人看的書,但有些內容對於瞭解的又過於基礎,這點體現在與作者想要透徹的寫原理,但是又由於篇幅限制有些地方卻草草略過,這對於我這種程度閱讀者來說明顯有點喫力,但這或許也是本書的特點,能迫使你自己動手去完善。所以,之後的章節會盡量少的貼書中的內容,多放些書中沒有而自己查的資料。再次提醒自己,認真對待!

4.1線程簡介

面試中面試官會問:說說Java線程吧。

我現在嘗試不看書,說說自己的認識:線程是操作系統調度的最小單元,一個應用程序會啓動多個線程,每個線程都有自己的棧內存,也就是說線程是相互獨立的。線程操作着自己所運行代碼的局部變量,方法參數,他們之間互不影響。線程間的通信通過共享內存機制進行,把內存中的變量拷貝到自己的工作空間之後寫會內存,當然這種方式會有問題,於是爲了避免線程在操作系統上的數據競爭等等,出現與我們預期功能不一致的問題,出現了很多控制方法如 volatile、加鎖、CAS、hapen-before規則或者一些高級用法,使得我們線程運行的不確定性能在我們的控制範圍內。

之後看書查資料:線程和進程明白講線程還是需要提到進程,需要擴張聯繫,這點需要加強。

  • 使用線程優勢:執行快,響應快,資源利用率(這是相互的,線程需要資源,資源需要利用)

  • 使用線程缺點:複雜,不確定性,安全

線程優先級

有優先級,操作系統不認。我猜可能是管理線程優先級的代價會比管理代碼的代價來的大。書上有測試程序,但沒興趣跑。

線程狀態

線程狀態很重要,在分析問題的時候要懂得看。

在書中的代碼

public class ThreadState {

    public static void main(String[] args) {
        new Thread(new TimeWaiting(),"TimeWaitingThread").start();
        new Thread(new Waiting(),"WaitingThread").start();
        new Thread(new Blocked(),"BlockedThread - 1").start();
        new Thread(new Blocked(),"BlockedThread - 2").start();
    }

    static class TimeWaiting implements Runnable{

        @Override
        public void run() {
            while (true) {
                try {
                    TimeUnit.SECONDS.sleep(100);
                } catch (InterruptedException e) {
                }
            }
        }
    }

    static class Waiting implements Runnable{

        @Override
        public void run() {
            while (true) {
                synchronized (Waiting.class){
                    try {
                        Waiting.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    static class Blocked implements Runnable{

        @Override
        public void run() {
            synchronized (Blocked.class) {
                while (true) {
                    try {
                        TimeUnit.SECONDS.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

運行

終端輸入jsp(查看在Java進程信息,windows在Java目錄下bin裏找)

輸出Java進程號 類名

終端輸入 jstack 剛纔的進程號
輸出

Java中運行就緒兩個狀態合併稱爲運行狀態

這裏還是引用資料 Java線程狀態切換以及核心方法

4.2 啓動和終止線程

在初始化的代碼中可以看到 如果在守護線程中創建線程,那麼創建的線程將繼承父線程的屬性也將編程守護線程。
代碼不貼,是Thread.javainit方法。

中斷概念很重要,書中我看內容並不多,所以要自己補充。
JAVA中斷機制詳解

suspend()resume()stop()廢棄

線程的終止使用中斷機制,在中斷後我們可以有後續操作比如回滾什麼的。

4.3 線程間通信

只說很重要的一點:
notify()notifyAll()方法調用後,等待線程依舊不會從wait()返回,需要調用上述方法的線程釋放鎖之後,等待線程才***有機會***從wait()返回。

等待通知的經典範式

等待方

  • 1 獲取對象鎖
  • 2 如果條件不滿足調用對象的wait()方法,被通知後仍要檢查條件。
  • 3 條件滿足則執行對應的邏輯
...
synchronized(鎖對象){
  while(條件){
        對象.wait();
  }
  後續處理
}

例如生產者消費者代碼片段

...
synchronized(queue){
    while(queue.size() == maxSize){
        try {
            System.out .println("Queue is full, Producer[" + name + "] thread waiting for " + "consumer to take something from queue.");
            queue.wait();
         } catch (Exception ex) {
            ex.printStackTrace();
         }
     }
}
...

通知方

  • 1獲得對象鎖
  • 2改變條件
  • 通知所有等待在對象上的線程
...
synchronized(鎖對象){
  改變條件
  對象.notifyAll();
}

例如生產者消費者代碼片段

...
synchronized(queue){
    int x = queue.poll();
    System.out.println("[" + name + "] Consuming value : " + x);
    queue.notifyAll();
}
...

構建線程安全類的一種法方 棧封閉
徹底理解ThreadLocal

線程應用實例

代碼最好自己敲一邊理解

最後想說一句——紙上得來終覺淺,絕知此事要躬行.

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