1. 程式人生 > >執行緒補充---執行緒的同步方法和通訊方法, 程序間的通訊

執行緒補充---執行緒的同步方法和通訊方法, 程序間的通訊

執行緒同步方法:

(1)同步方法:

  • 即有synchronized關鍵字修飾的方法。 由於java的每個物件都有一個內建鎖,當用此關鍵字修飾方法時,內建鎖會保護整個方法。在呼叫該方法前,需要獲得內建鎖,否則就處於阻塞狀態。
  • 注: synchronized關鍵字也可以修飾靜態方法,此時如果呼叫該靜態方法,將會鎖住整個類

(2)同步程式碼塊

  • 即有synchronized關鍵字修飾的語句塊。被該關鍵字修飾的語句塊會自動被加上內建鎖,從而實現同步
    注:同步是一種高開銷的操作,因此應該儘量減少同步的內容。通常沒有必要同步整個方法,使用synchronized程式碼塊同步關鍵程式碼即可。

(3)使用特殊域變數(Volatile)實現執行緒同步

  • a.volatile關鍵字為域變數的訪問提供了一種免鎖機制
  • b.使用volatile修飾域相當於告訴虛擬機器該域可能會被其他執行緒更新
  • c.因此每次使用該域就要重新計算,而不是使用暫存器中的值d.volatile不會提供任何原子操作,它也不能用來修飾final型別的變數
  • 它的原理是每次要執行緒要訪問volatile修飾的變數時都是從記憶體中讀取,而不是存快取當中讀取,因此每個執行緒訪問到的變數值都是一樣的。這樣就保證了同步。

4)使用重入鎖實現執行緒同步

  • 在JavaSE5.0中新增了一個java.util.concurrent包來支援同步。
  • ReentrantLock類是可重入、互斥、實現了Lock介面的鎖, 它與使用synchronized方法和快具有相同的基本行為和語義,並且擴充套件了其能力。
  • ReenreantLock類的常用方法有:ReentrantLock() : 建立一個ReentrantLock例項lock() : 獲得鎖unlock() : 釋放鎖
  • 注:ReentrantLock()還有一個可以建立公平鎖的構造方法,但由於能大幅度降低程式執行效率,不推薦使用
  • 如果synchronized關鍵字能滿足使用者的需求,就用synchronized,因為它能簡化程式碼 。如果需要更高階的功能,就用ReentrantLock類,此時要注意及時釋放鎖,否則會出現死鎖,通常在finally程式碼釋放鎖

(5)使用區域性變數實現執行緒同步

  • 如果使用ThreadLocal管理變數,則每一個使用該變數的執行緒都獲得該變數的副本,副本之間相互獨立,這樣每一個執行緒都可以隨意修改自己的變數副本,而不會對其他執行緒產生影響。現在明白了吧,原來每個執行緒執行的都是一個副本,也就是說存錢和取錢是兩個賬戶,知識名字相同而已。所以就會發生上面的效果。

  • ThreadLocal與同步機制

  • a.ThreadLocal與同步機制都是為了解決多執行緒中相同變數的訪問衝突問題

  • b.前者採用以”空間換時間”的方法,後者採用以”時間換空間”的方式

執行緒間的通訊手段:

①同步

這裡講的同步是指多個執行緒通過synchronized關鍵字這種方式來實現執行緒間的通訊。

由於執行緒A和執行緒B持有同一個MyObject類的物件object,儘管這兩個執行緒需要呼叫不同的方法,但是它們是同步執行的,比如:執行緒B需要等待執行緒A執行完了methodA()方法之後,它才能執行methodB()方法。這樣,執行緒A和執行緒B就實現了 通訊。

這種方式,本質上就是“共享記憶體”式的通訊。多個執行緒需要訪問同一個共享變數,誰拿到了鎖(獲得了訪問許可權),誰就可以執行。

②while輪詢的方式

在這種方式下,執行緒A不斷地改變條件,執行緒ThreadB不停地通過while語句檢測這個條件(list.size()==5)是否成立 ,從而實現了執行緒間的通訊。但是這種方式會浪費CPU資源。之所以說它浪費資源,是因為JVM排程器將CPU交給執行緒B執行時,它沒做啥“有用”的工作,只是在不斷地測試 某個條件是否成立。就類似於現實生活中,某個人一直看著手機螢幕是否有電話來了,而不是: 在幹別的事情,當有電話來時,響鈴通知TA電話來了。

③wait/notify機制

程序間的通訊方式

(1) 管道(PIPE)
(2) 命名管道(FIFO)
(3) 訊號燈(Semphore)
(4) 訊息佇列(MessageQueue)
(5) 共享記憶體(SharedMemory)
(6) Socket(當然也有Socket)