天天看點

java 多線程基礎(二)

  1. 什麼是線程?

    作業系統是包含多個程序的容器,而每個程序又是容納了多個線程的容器。

    java 多線程基礎(二)
    從圖中可以看出 一個作業系統同時可以有多個子程序,一個程序可以有多個子線程但一個子線程隻能有一個父程序。

建立你的第一個java多線程程式:

public class Creat100Threads {

    /**
     * 建立一百個線程
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {
        for(int i=0;i<100;i++){
            new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}
           
java 多線程基礎(二)

運作代碼後 多了100個線程 可以看到 程式确實實作了線程。

線程和程序的不同

  • .程序和線程的定義不同
    • 程序:是執行中一段程式,即一旦程式被載入到記憶體中并準備執行,它就是一個程序。程序是表示資源配置設定的的基本概念,又是排程運作的基本機關,是系統中的并發執行的機關。
    • 線程:單個程序中執行中每個任務就是一個線程。線程是程序中執行運算的最小機關,是cpu排程的基本機關。
  • 記憶體共享方式不同:
    • 程序是互相獨立的:不同程序會被作業系統配置設定一定記憶體空間,但通常不同程序之間記憶體是獨立的無法互相通路。如果要實作程序間通訊需要用到"程序間通信(IPC)"。
    • 線程之間特定資源是共享的:線程共享資源包括:
    1. 程序代碼段
    2. 程序的公有資料(利用這些共享資料,線程很容易實作互相通訊)
    3. 程序打開檔案掃描符
    4. 信号處理器
    5. 程序的目前目錄
    6. 程序使用者ID與程序組ID
    • 線程獨有内容:
    1. 線程ID
    2. 寄存器組的值
    3. 線程的堆棧
    4. 錯誤傳回碼
    5. 線程的屏蔽新号碼
  • 數量不同
    • 一個程序至少有一個或以上線程, 一個線程隻能有一個父程序。
  • 開銷不同
    1. 線程的建立、終止時間比程序段
    2. 同一程序内的線程切換時間比程序短
    3. 同 一程序的各個線程間共享記憶體和檔案資源,可不通過核心進行通信。

Java語言和多線程的淵源和關系

  • Java設計之初–支援多線程(受限于硬體當時很多語言并不支援多線程)
  • Java語言在服務端開發語言中的地位–常年居榜前三(阿裡 騰訊 百度 美團。。。)
  • 一對一映射到作業系統的核心線程(java中的多線程會在作業系統核心 中一一對應建立多線程)
  • jvm自動啟動線程
    java 多線程基礎(二)

    啟動一個隻有main方法的java程式可以看到除了main線程還jvm還幫我們啟動了其他線程,這裡面啟動的線程有

    Finalizer:負責對象的Finalizer()方法

    Signal Dispatcher 負責把作業系統發來的信号分發給适當的程式處理

    Reference Handler GC、引用相關線程(java的垃圾回收)

    main 主線程,使用者程式的入口。

多線程

什麼是多線程?

多線程的概念:如果一個程式允許兩個或以上的線程,那麼它就是多線程程式。多線程市值在單個程序中運作多個線程。

生活中的多線程:

比喻你和室友同住一間房

  • 客廳(程序的記憶體空間)
  • 廁所(隻能有一個人上廁所 上廁所時其他人不能上 鎖的概念)
  • 獨立房間(每個線程 有自己的ID 堆棧)
  • 打掃(一個人打掃效率比較慢 在公共區域可能會一起協作打掃 )
  • 吃火鍋
    • 大火鍋一人吃(相當于 單程序單線程)
    • 大火鍋一起吃 (單程序 多線程)
    • 一個人吃多個小火鍋(多程序)
    • 吃火鍋底料(有人霸占了這些火鍋(鎖) 那你就吃不到了)

什麼是多線程?

多線程實際例子:搶火車票

java 多線程基礎(二)

如果各個任務互相獨立 互不影響 則不需要多線程。

java 多線程基礎(二)

但絕大多數場景不同的任務 是互相耦合影響的,這時候就需要多線程。

為什麼需要多線程?

  • 最主要是提高cpu利用效率

    -cpu一個時鐘周期 是非常快的 相對于記憶體 和 硬碟來說 是跟不上 cpu這個速度的 如果 為了響應 cpu 記憶體 的處理的資料 那會大大拖累cpu的性能。那cpu在這個等到記憶體 等外部裝置處理的、過程中就會浪費資源。而多線程就是提高cpu的資源使用率。

  • 提高使用者體驗:避免卡頓、縮短等待時間
    • 并行處理,提高性能,通常是服務領域(例如timcat),用多個線程去接收進來的Http請求,而不是排隊等待單一的線程處理。
    • 在Android開發中,主線程的重要任務之一是繪制螢幕界面,該線程中不允許進行IO操作或網絡請求,目的是避免卡頓,影響使用者互動。
  • 便于程式員設計程式設計模型(将一個功能分割成若幹不同子線程)
  • 阿姆達定律

    -處理器越多,程式就執行越快,但有上限,取決于程式中串行部分的比例,并行比例越高多處理器性能優勢越明顯。

    java 多線程基礎(二)
    由于摩爾定律的逐漸失效 單主頻提升越來越不明顯,要想提升程式速度 需要靠程式提高并行處理的能力。

什麼場景會用到多線程?

  • 同時處理不同的事:1. 聽音樂 2. 背景定時任務,execel
  • 同時提高工作效率:1. tomecat 2. 并行下載下傳 3. NIO
  • 需要很大并發量的時候

多線程的局限

  • 性能問題:上下文切換帶來的問題
  • 異構化任務: (任務結構不一樣)很難高效并行
  • 帶來線程安全問題:包括資料安全問題(例如i++ 總數不一緻) 以及線程帶來的活躍性問題(線程饑餓、死鎖)

串行、并行、并發

  • 串行和并行
    java 多線程基礎(二)
    打個比方 串行就是你數羊毛一次數1根1根的 而并行 是十根十根一起數。
  • 并行、并發
    java 多線程基礎(二)

    在隻有一個cpu的情況下 但是 你的音樂 QQ 都能 同時運作 互相切換 就是cpu處于并行運算 将cpu的片段是在不同程序中切換配置設定的。這時cpu相當于在邏輯上并行處理多個應用。

    而當有多個cpu時 程式跑在真實的不同實體cpu上這時就是并發了。

    java 多線程基礎(二)
  • 真正的"同時"運作-在同一時刻,有多個任務同時執行。

    例如,在多核處理器上,有兩個線程同時執行一段代碼。

    相反的,單核cpu是無法處理并發任務的。

并發的2種概念

  1. 形容多個任務的執行狀态
    • 兩個或多個任務可以再重疊的時間段内啟動,運作和完成
    • 并發(兩個線程同時執行)一定是并發

      p a r a l l e l i s m ∈ C o n c u r r e n c y parallelism \in Concurrency parallelism∈Concurrency

      可以說:并發是并行的充分條件,并行是并發的必要條件。

      java 多線程基礎(二)
  2. 對"并發性"的簡稱
    • 不同部分可以無序或同時執行,且并不會影響最終的執行結果。
    • 在不同核心數的計算機上的不同表現

串并行和并發的實際例子

  • 打遊戲時,女朋友來電話

    假設 大腦是單核cpu

    并行:此時 如果你選擇繼續打遊戲并且 接電話 但受限于你的大腦是單核的 你的思維就隻能在這之間不同切換,此時就是并行。

    串行:此時你選擇暫時不接電話,等遊戲結束後 再打電話給女朋友 ,此時就是串行,每次隻處理一件事。

    一個程式能并行運作一定具有并發性。

是什麼讓并發和并行成為可能?

  • CPU更新
  • 作業系統更新
  • 程式設計語言更新

高并發

  • 什麼是高并發(雙十一 春晚 12306)
    • 是系統 同時能夠處理大量的不求請求的能力。
  • 高并發和多線程的聯系和不同?
    • 多線程是高并發的一種重要的解決方案,多線程并不意味着高并發,如Redis 是單線程的同時也是能處理大量的請求。
  • 高并發有哪些名額

    -QPS(Queries Per Second) 每秒的查詢數

    • 帶寬
    • PV(Page View)
    • UV(Unique Visitor)
    • IP 和 UV 的差別
    • 并發連接配接數(The number of concurrency)
    • 伺服器平均請求等待時間 (Time per request:across all concurrent requests)

同步與異步、阻塞與非阻塞

  • 同步與異步:被調用者主動告訴調用者結果
  • 阻塞與非阻塞:我是調用者,我調用一個東西以後,結果傳回前,是否還能處理其他事情。
java 多線程基礎(二)

如上圖 在EVENT調用後 有一段等待時間 電腦是不會做其他事情的 直到結果傳回前,此時電腦資源被白白的耗費着。

java 多線程基礎(二)

異步就不同了在發送一個請求後在伺服器響應前 電腦又去處理其他請求了。 就相當于你燒白開水 同步的話你就守在水壺面前什麼也不幹 直到水壺燒開 開關跳掉 但我相信平時你坑定不會這麼做 更多的是異步 燒開水時你去幹别的事等 燒開 等電源跳掉 你聽到了 再去取。

java 多線程基礎(二)

同步:同步異步這裡指的是被調用者(也就是伺服器)的行為,而不是請求方的行為。在沒有得到結果這錢,服務端就不傳回任何結果。

異步:調用在發出之後,服務端立刻傳回,告訴調用方”我收到你的請求了,我會處理的“。

再打個比方 你去借書 問老闆有沒有這本書老闆說 我幫你找找 然後過了一小時你就去問老闆 書有沒有找到 這時同步的一種思想 與此相對的是 當你去問老闆的時候老闆說 我先幫你找找 你留個電話找到了我再打電話給你這就相當于異步 回調了你的電話。

阻塞和非阻塞

  • 站線上程狀态的角度
  • 站線上程送出請求(通常是HTTP請求)的角度
  • 阻塞非阻塞的栗子:燒水壺、買書

    還是借書的栗子 如果在你問了老闆之後 你如果去幹了别的事情那這就是非阻塞。當然如果你一直等着老闆 那就是阻塞。

    燒開水 同樣也是 你可以在燒毀的同時去看電視 等到 水壺發出 嗚嗚嗚的聲音你再處理。這樣就是異步非阻塞。如果你一直等着 但是等聽到水壺發出嗚嗚嗚 的聲音 你再去處理 這就是 異步阻塞 所謂的異步就是讓被調用者 主動觸發 調用者 來實作而同步與此相反 就是水壺不會發出 嗚嗚嗚 的聲音你必須時不時的去看 這水壺燒開沒有 。

繼續閱讀