併發編程(JAVA版)-------------(三)

本文承接一併發編程(JAVA版)-------------(一)

本文承接二併發編程(JAVA版)-------------(二)

共享模型之管程

面對共享資源的重要知識:原子性,對象的選擇

  • synchronized實際是用對象鎖保證了臨界區內代碼的原子性,臨界區內的代碼對外是不可分割的,不會被線程切換所打斷。
    關於線程的理解,可以上網搜一下線程八鎖問題,這個是我在學習的過程中覺得非常不錯的關於線程理解的問題,看一下總歸是有好處的,你們隨意,要是覺得好的話,記得回來點個贊,支持一下博主,你們的支持是我最大的動力。

變量的線程安全分析

成員變量和靜態變量是否線程安全?

  • 如果它們沒有共享,則線程安全
  • 如果它們被共享了,根據它們的狀態是否能夠改變又分兩種狀態:
    • 如果只有讀操作,則線程安全
    • 如果有讀寫操作,則這段代碼是臨界區,需要考慮線程安全

局部變量是否線程安全?

  • 局部變量是線程安全的
  • 但局部變量引用的對象則未必
    • 如果該對象沒有逃離方法的作用訪問,它是線程安全的
    • 如果該對象逃離方法的作用範圍,則需要考慮線程安全(可用final、private來加強安全性)

常見的線程安全類

  • String
  • Integer
  • StringBuffer
  • Random
  • Vector
  • Hashtable
  • jave.util.concurrent包下的類(簡稱JUC)
    這裏說它們是線程安全的是指,多個線程調用它們同一個實例的某個方法時,線程是安全的。也可以理解爲:
Hashtable table = new Hashtable();
new Thread(()->{
	table.put("key","value1");
}).start();
new Thread(()->{
	table.put("key","value2");
}).start();
  • 它們的每一個方法是原子的
  • 注意它們多個方法的組合不是原子的,見後面的分析

不可變類線程安全性

String、Integer等都是不可變類,因爲其內部的狀態不可以改變,因此它們的方法都是線程安全的。
說到這裏,肯定就有同學有疑問,String有replace、substring等方法【可以】改變值啊,那麼這些方法又是如何保證線程安全的呢?
答案是通過閱讀源碼可以瞭解,在這些方法裏通過新建對象來保證線程安全。

Monitor(鎖)工作原理

Monitor被翻譯爲監視器管程
每個Java對象都可以關聯一個Monitor對象,如果使用synchronized給對象上鎖(重量級)之後,該對象頭的Mark Word中就被設置指向Monitor對象的指針

  • 剛開始Monitor中Owner爲null
  • 當Thread2執行synchronized(obj)就會將Monitor的所有者Owner置爲Thread2,Monitor中只能有一個Owner
  • 在Thread2上鎖的過程中,如果Thread3,Thread4,Thread5也來執行synchronized(obj),就會進入EntryList BLOCKED
  • Thread2執行完同步代碼塊的內容,然後喚醒EntryList中等待的線程來競爭鎖,競爭的時候是非公平的,是由JDK底層實現決定的

注意

  • synchronized必須是進入同一個對象的monitor纔有上述效果
  • 不加synchronized的對象不會關聯監視器,不遵循以上規則
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章