- java代碼在編譯後會變成java的位元組碼,位元組碼會被類加載器加載到jvm裡,jvm執行位元組碼,最終轉化為彙編指令在cpu上運作,這個過程是java代碼執行的基本原理,程式設計的最終還是與cpu和記憶體的互動,多線程程式設計帶來的挑戰之一便是如何能讓多個線程同時執行一個任務的時候不出錯? 具體到同時修改一個變量的時候如何不出錯? java底層基本是通過“鎖”的概念來做。
- java中有兩個常見的鎖,volatile和synchronized
volatile關鍵字原理
- volatile關鍵字的定義是:java程式設計語言允許線程通路共享變量,為了保證共享變量能被準确和一緻的更新,線程應該確定通過排他鎖擷取這個變量。
- 通過定義我們可以知道這個關鍵字的幾個特點: 1,修飾的是共享的變量【不能修飾方法和類】 2,隻保證可見性,不保證一緻性。 3,為了保證一緻性,修改的時候必須添加排它鎖。
- volatile的有兩條實作的原則: 1,lock字首指令會引發處理器緩存寫回到記憶體 2,第一步操作會使得其他處理器的該變量的緩存失效。
-
lock字首指令會引發處理器緩存寫回到記憶體
當處理器修改volatile修飾的變量的時候,會引起處理器的緩存寫回到主記憶體,但是一般不會鎖定整個總線,而是鎖定緩存。
-
第一步操作會使得其他處理器的該變量的緩存失效
處理器會有嗅探技術對volatile修飾的變量進行監控,如果有寫會的操作,緩存失效,則會通知定義嗅探的線程。原理類似于監聽。
- volatile的使用優化:
- 有一種優化的方式,是為緩存行追加位元組,使得其變為64位元組這種優化的方式是有些處理器的高速緩存行的位元組數為64位元組寬,如果沒有追加的話,多個緩存行可能會被放入同一個高速緩存行,當有寫操作的時候,整個行被鎖定。 有兩種情況下可以不追加 1,處理器的高速緩存行不是64, 2 共享變量不會頻繁的寫導緻緩存鎖定。
synchronized關鍵字原理
- java存在并發程式設計之初,synchronized就一直存在,可謂是元老級的鎖,很多人稱之為重量級鎖,随1.6的各種優化,synchronized并沒有那麼重了, 1.6為了減少擷取鎖和釋放鎖帶來的性能消耗引入了偏向鎖和輕量級的鎖。
- synchronized可以修飾變量,方法,類。
- synchronized修飾普通的方法: 鎖定目前的執行個體對象。
- synchronized修飾靜态方法: 鎖定目前類的class對象。
- synchronized修飾同步方法塊:鎖定方法塊裡的配置的對象。
- synchronized在jvm的實作原理基于進入和退出Monitor對象來實作方法和方法塊的同步。
【偏向鎖】: 簡單的來說就是一個鎖對線程有偏向的意思,在java中鎖一共有四種狀态,由高到低依次為無狀态鎖,偏向鎖,輕量級鎖,重量級鎖。