并发编程之Synchronized原理
一、基本使用
? ?1.Synchronized的作用。
- 原子性:確保線程互斥的訪問同步代碼;
- 可見性:保證共享變量的修改能夠及時可見,其實是通過Java內存模型中的 “對一個變量unlock操作之前,必須要同步到主內存中;如果對一個變量進行lock操作,則將會清空工作內存中此變量的值,在執行引擎使用此變量前,需要重新從主內存中load操作或assign操作初始化變量值” 來保證的;
- 有序性:有效解決重排序問題,即 “一個unlock操作先行發生(happen-before)于后面對同一個鎖的lock操作”;
- 當synchronized作用在實例方法時,監視器鎖(monitor)便是對象實例(this);
- 當synchronized作用在靜態方法時,監視器鎖(monitor)便是對象的Class實例,因為Class數據存在于永久代,因此靜態方法鎖相當于該類的一個全局鎖;
- 當synchronized作用在某一個對象實例時,監視器鎖(monitor)便是括號括起來的對象實例。
? 3.synchronized與Lock的區別
? 1.首先synchronized是java內置關鍵字,在jvm層面,Lock是個java類;
? 2.synchronized無法判斷是否獲取鎖的狀態,Lock可以判斷是否獲取到鎖;
? 3.synchronized會自動釋放鎖(a?線程執行完同步代碼會釋放鎖 ;b 線程執行過程中發生異常會釋放鎖),Lock需在finally中手工釋放鎖(unlock()方法釋放鎖),否則容易造成線程死鎖;
? 4.用synchronized關鍵字的兩個線程1和線程2,如果當前線程1獲得鎖,線程2線程等待。如果線程1阻塞,線程2則會一直等待下去,而Lock鎖就不一定會等待下去,如果嘗試獲取不到鎖,線程可以不用一直等待就結束了;
? 5.synchronized的鎖可重入、不可中斷、非公平,而Lock鎖可重入、可判斷、可公平(兩者皆可)
? 6.Lock鎖適合大量同步的代碼的同步問題,synchronized鎖適合代碼少量的同步問題。
| 存在層次 | Java的關鍵字,在jvm層面上 | 是一個類 |
| 鎖的釋放 | 1、以獲取鎖的線程執行完同步代碼,釋放鎖 2、線程執行發生異常,jvm會讓線程釋放鎖 | 在finally中必須釋放鎖,不然容易造成線程死鎖 |
| 鎖的獲取 | 假設A線程獲得鎖,B線程等待。如果A線程阻塞,B線程會一直等待 | 分情況而定,Lock有多個鎖獲取的方式,具體下面會說道,大致就是可以嘗試獲得鎖,線程可以不用一直等待 |
| 鎖狀態 | 無法判斷 | 可以判斷 |
| 鎖類型 | 可重入 不可中斷 非公平 | 可重入 可判斷 可公平(兩者皆可) |
| 性能 | 少量同步 | 大量同步 |
1.數據同步需要依賴鎖,那鎖的同步又依賴誰?
?synchronized:在軟件層面依賴JVM。
?j.u.c.Lock:在硬件層面依賴特殊的CPU指令。
2.監視器鎖(monitor):每個對象都是一個監視器鎖(monitor)。
??Synchronized的語義底層是通過一個monitor的對象來完成。
3.monitorenter:每個對象都是一個監視器鎖(monitor)。當monitor被占用時就會處于鎖定狀態,線程執行monitorenter指令時嘗試獲取monitor的所有權。
- 如果monitor的進入數為0,則該線程進入monitor,然后將進入數設置為1,該線程即為monitor的所有者;
- 如果線程已經占有該monitor,只是重新進入,則進入monitor的進入數加1;
- 如果其他線程已經占用了monitor,則該線程進入阻塞狀態,直到monitor的進入數為0,再重新嘗試獲取monitor的所有權;
4.monitorexit:執行monitorexit的線程必須是objectref所對應的monitor的所有者。指令執行時,monitor的進入數減1,如果減1后進入數為0,那線程退出monitor,不再是這個monitor的所有者。其他被這個monitor阻塞的線程可以嘗試去獲取這個 monitor 的所有權。
三、同步概念
1.Java對象頭
? 對象在內存中的布局分為三塊區域:對象頭、實例數據和對齊填充。
- 實例數據:存放類的屬性數據信息,包括父類的屬性信息;
- 對齊填充:由于虛擬機要求 對象起始地址必須是8字節的整數倍。填充數據不是必須存在的,僅僅是為了字節對齊;
- 對象頭:Java對象頭一般占有2個機器碼(在32位虛擬機中,1個機器碼等于4字節,也就是32bit,在64位虛擬機中,1個機器碼是8個字節,也就是64bit),但是 如果對象是數組類型,則需要3個機器碼,因為JVM虛擬機可以通過Java對象的元數據信息確定Java對象的大小,但是無法從數組的元數據來確認數組的大小,所以用一塊來記錄數組長度。
??
?2.對象頭中Mark Word與線程中Lock Record
?3.監視器(Monitor)
?任何一個對象都有一個Monitor與之關聯,當且一個Monitor被持有后,它將處于鎖定狀態。
?Synchronized在JVM里的實現都是?基于進入和退出Monitor對象來實現方法同步和代碼塊同步。
?3.1?MonitorEnter指令:插入在同步代碼塊的開始位置,當代碼執行到該指令時,將會嘗試獲取該對象Monitor的所有權,即嘗試獲得該對象的鎖;
?3.2 MonitorExit指令:插入在方法結束處和異常處,JVM保證每個MonitorEnter必須有對應的MonitorExit;
?參考:深入分析Synchronized原理。
?
轉載于:https://www.cnblogs.com/wenxiangchen/p/11340799.html
總結
以上是生活随笔為你收集整理的并发编程之Synchronized原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mysql索引底层实现
- 下一篇: Windows Azure Storag