細說多線程

  • JAVA線程

  • java線程實現方式

    • 實現runnable接口(無結果返回)
    • 實現callable接口 (可以通過Future獲取返回執行結果)
    • 直接繼承Thread類(爲一個實現runnable接口類的實例) 
  • Java 創建線程代價

    • 關於時間,創建線程使用是直接向系統申請資源的,這裏調用系統函數進行分配資源的話耗時不好說。對操作系統來說,創建一個線程的代價是十分昂貴的, 需要給它分配內存、列入調度,同時在線程切換的時候還要執行內存換頁,CPU 的緩存被 清空,切換回來的時候還要重新從內存中讀取信息,破壞了數據的局部性
    • 關於資源,Java線程的線程棧所佔用的內存是在Java堆外的,所以是不受java程序控制的,只受系統資源限制,默認一個線程的線程棧大小是1M(當讓這個可以通過設置-Xss屬性設置,但是要注意棧溢出問題),但是,如果每個用戶請求都新建線程的話,1024個用戶光線程就佔用了1個G的內存,如果系統比較大的話,一下子系統資源就不夠用了,最後程序就崩潰了。
  • Java線程的狀態

    • new(初始狀態) ---》 可運行(start|| submit) ----> 運行(獲得CPU使用權)---》 dead || 不可運行狀態
    • 不可運行狀態 :
      • 1,block 調用sleep || jion方法, 不會釋放線程monitor)放棄CPU使用權
      • 2,lock 調用同步方法失敗,被放入到等待線程對列排隊. 繼續爭搶monitor權限。才能獲取自由freedom...
      • 3,waiting 調用wait()方法, 放棄對象monitor權限, 被扔到等待對列, 等待notify方法, 或者notifyall()喚醒
    • dead
      • 線程代碼執行結束或者出現異常退出,,, 
  • 線程池 

    • 存在的意義
      • 降低使用線程代價,(節約系統創建線程, 銷燬線程的時間)
      • a. 重用存在的線程,減少對象創建、消亡的開銷,性能佳。 
      • b. 可有效控制最大併發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。 
      • c. 提供定時執行、定期執行、單線程、併發數控制等功能。
    • 線程池實現
    • 原理
      • 1、線程池管理器(ThreadPool):用於創建並管理線程池,包括 創建線程池,銷燬線程池,添加新任務;
      • 2、工作線程(PoolWorker):線程池中線程,在沒有任務時處於等待狀態,可以循環的執行任務;
      • 3、任務接口(Task):每個任務必須實現的接口,以供工作線程調度任務的執行,它主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀態等;
      • 4、任務隊列(taskQueue):用於存放沒有處理的任務。提供一種緩衝機制。
    • 常用線程池:ExecutorService 是主要的實現類,其中常用的有 : Executors.newSingleThreadPool() 之創建一個線程執行任務

      newFixedThreadPool() 固定數目線程數

      newcachedTheadPool() 使用時才創建線程

       newScheduledThreadPool()

  • 參考文檔鏈接地址

JAVA多線程同步

WHY-同步
  • 因爲當我們有多個線程要同時訪問一個變量或對象時,如果這些線程中既有讀又有寫操作時,就會導致變量值或對象的狀態出現混亂,從而導致程序異常。舉個例子,如果一個銀行賬戶同時被兩個線程操作,一個取100塊,一個存錢100塊。假設賬戶原本有0塊,如果取錢線程和存錢線程同時發生,會出現什麼結果呢?取錢不成功,賬戶餘額是100.取錢成功了,賬戶餘額是0.那到底是哪個呢?很難說清楚。因此多線程同步就是要解決這個問題。
同步方式
  • 1: synchronized 修飾方法

    • 即有synchronized關鍵字修飾的方法。 由於java的每個對象都有一個內置鎖,當用此關鍵字修飾方法時,內置鎖會保護整個方法。在調用該方法前,需要獲得內置鎖,否則就處於阻塞狀態。
    • Tips:synchronized關鍵字也可以修飾靜態方法,此時如果調用該靜態方法,將會鎖住整個類
  • 2: synchronized 修飾代碼塊

    • synchronized 修飾的邏輯越少代碼執行效率就越高(同步是一種高開銷的操作,因此應該儘量減少同步的內容。通常沒有必要同步整個方法,使用synchronized代碼塊同步關鍵代碼即可。)
  • 3: 使用特殊域變量(Volatile)實現線程同步(該實現可能會有問題-- 加鎖機制既可以確保可見性又可以確保原子性,而volatile變量只有確保可見性。)

    • a.volatile關鍵字爲域變量的訪問提供了一種免鎖機制
    • b.使用volatile修飾域相當於告訴虛擬機該域可能會被其他線程更新
    • c.因此每次使用該域就要重新計算,而不是使用寄存器中的值
    • d.volatile不會提供任何原子操作,它也不能用來修飾final類型的變量 (這點很關鍵, 它只能提供變量的原子訪問,可內存讀寫可見,但是不能保證操作數據過程的原子)
  • 4: 使用重入鎖實現線程同步(ReentrantLock)

    • ReentrantLock類是可重入、互斥、實現了Lock接口的鎖, 它與使用synchronized方法和快具有相同的基本行爲和語義,並且擴展了其能力。ReenreantLock類的常用方法有:ReentrantLock() : 創建 ReentrantLock實例 lock() : 獲得鎖 unlock() : 釋放鎖

    • Tips:ReentrantLock()還有一個可以創建公平鎖的構造方法,但由於能大幅度降低程序運行效率,不推薦使用

  • (5)使用局部變量實現線程同步

    • threadLocal
    • 使的線程擁有變量私有備份,使用線程私有變量threadLocalMap 進行變量管理(使用Thread)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章