volatile 與 synchronize 詳解
Java支援多個執行緒同時訪問一個物件或者物件的成員變數,由於每個執行緒可以擁有這個變數的拷貝(雖然物件以及成員變數分配的記憶體是在共享記憶體中的,但是每個執行的執行緒還是可以擁有一份拷貝,這樣做的目的是加速程式的執行,這是現代多核處理器的一個顯著特性),所以程式在執行過程中,一個執行緒看到的變數並不一定是最新的。
volatile
volatile的應用
在多執行緒併發程式設計中 synchronized 和 volatile 都扮演著重要的角色,volatile 是一個輕量級的 synchronized ,它在多處理器開發中保證了共享變數的 可見性。可見性的意思是當一個執行緒修改一個共享變數的時候,另一個執行緒能讀取到這個共享變數被修改後的值。如果 volatile 使用恰當的話,它比 synchronized的使用和執行成本更低,因為volatile不會引起執行緒上下文的切換和排程
volatile的定義與實現原理
Java程式語言允許執行緒訪問共享變數,為了確保共享變數能被準確和一致性地更新,執行緒應該確保通過排他鎖來單獨獲取這個變數。Java提供的volatile在某些情況下比鎖要方便。如果一個欄位被宣告為volatile,那麼Java模型確保所有的執行緒看到這個變數的值是一致的
volatile的兩條實現原則
- Lock字首指令會引起處理器快取回寫到記憶體
- 一個處理器的快取回寫到記憶體會導致其他的處理器的快取無效
synchronized
synchronized關鍵字可以修飾方法或者以同步塊的形式來進行使用,它主要確保多個執行緒在同一個時刻,只能有一個執行緒處於方法或者同步塊中,它保證了執行緒對變數訪問的可見性和排他性
synchronized的實現原理與應用
在多執行緒併發程式設計中 synchronized 一直是元老級的角色,很多人都會直呼它為重量級鎖。但是,隨著Java SE 1.6對 synchronized進行了各種優化之後,有些情況下synchronized並沒有那麼重了
synchronized如何實現同步?
synchronized實現同步的基礎:Java中的每一個物件都可以作為鎖。具體的表現形式有以下三種:
- 對於普通同步方法,鎖是當前例項物件
- 對於靜態同步方法,鎖是當前類的Class物件
- 對於同步方法塊,鎖是synchronized括號裡配置的物件
當一個執行緒試圖訪問同步程式碼塊時,必須先獲取到鎖,退出或丟擲異常時必須釋放鎖
volatile 與 synchronized 的區別?
volatile | synchronized | |
---|---|---|
修飾 | 只能用於修飾變數 | 可以用於修飾方法、程式碼塊 |
執行緒阻塞 | 不會發生執行緒阻塞 | 會發生阻塞 |
原子性 | 不能保證變數的原子性 | 可以保證變數原子性 |
可見性 | 可以保證變數線上程之間訪問資源的可見性 | 可以間接保證可見性,因為它會將私有記憶體中和公共記憶體中的資料做同步 |
同步性 | 能保證變數在私有記憶體和主記憶體間的同步 | synchronize是多執行緒之間訪問資源的同步性 |
- volatile是執行緒同步的輕量級實現,所以volatile的效能要比synchronize好;隨著jdk技術的發展,synchronize在執行效率上會得到較大提升,所以synchronize在專案過程中還是較為常見的
- 對於volatile修飾的變數,可以解決變數讀時可見性問題,無法保證原子性。對於多執行緒訪問同一個例項變數還是需要加鎖同步
在多執行緒定義中,volatile關鍵字主要是在屬性上使用的,表示此屬性為直接資料操作,而不進行副本的拷貝處理。這樣的話在一些書上就將其錯誤的理解為同步屬性了。
package com.java.springtest.test;
/**
* @author Woo_home
* @create by 2020/1/20
*/
public class ThreadDemo {
public static void main(String[] args) throws Exception{
ThreadShop shopA = new ThreadShop();
ThreadShop shopB = new ThreadShop();
ThreadShop shopC = new ThreadShop();
new Thread(shopA,"A 店鋪").start();
new Thread(shopB,"B 店鋪").start();
new Thread(shopC,"C 店鋪").start();
}
}
class ThreadShop implements Runnable {
private volatile int product = 5; // 直接記憶體操作
@Override
public void run() {
synchronized (this) {
while (this.product > 0) {
try {
Thread.sleep(100);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "商品處理,product = " + this.product--);
}
}
}
}
在正常進行變數處理的時候往往會經歷如下的幾個步驟:
- 獲取變數原有的資料內容副本;
- 利用副本為變數進行數學計算;
- 將計算後的變數,儲存到原始空間之中;
而如果一個屬性上追加了volatile關鍵字,表示的就是不使用副本,而是直接操作原始變數,相當於節約了拷貝副本、重新儲存的步驟
面試題: 請解釋volatile與synchronized的區別?
1)volatile主要在屬性上使用,而synchronized是在程式碼塊與方法上使用;
2)volatile無法描述同步的處理,它只是一種直接記憶體的處理,避免了副本的操作,而synchronized是實現同步的。
相關文章
- 全面解讀volatile和synchronize,輕鬆掌握Volatile與Synchronizedsynchronized
- volatile使用詳解
- 程式設計師:不能逃避的synchronize和volatile程式設計師
- Java 之 volatile 詳解Java
- volatile底層原理詳解
- Java 併發機制底層實現 —— volatile 原理、synchronize 鎖優化機制Java優化
- C/C++中volatile關鍵字詳解C++
- 詳解鎖原理,synchronized、volatile+cas底層實現synchronized
- Java併發程式設計:JMM (Java記憶體模型) 以及與volatile關鍵字詳解Java程式設計記憶體模型
- Synchronize 關鍵字原理
- synchronize關鍵字 原理
- Synchronize和ReentrantLock區別ReentrantLock
- volatile與synchronized的區別synchronized
- 基礎篇:詳解鎖原理,volatile+cas、synchronized的底層實現synchronized
- Cookie與Session詳解CookieSession
- rowspan 與 colspan 詳解
- fork與vfork詳解
- volatile的語義與實踐
- java synchronize - 執行緒同步機制Java執行緒
- 六、面試必問——volatile作用與原理面試
- ThinkPHP與UCenter整合詳解PHP
- Unicode與JavaScript詳解UnicodeJavaScript
- Dockerfile - 引數與詳解Docker
- Java 執行緒和 volatile 解釋Java執行緒
- 兩分鐘瞭解Java中volatile!Java
- 詳解not in與not exists的區別與用法
- Volatile關鍵字與執行緒安全執行緒
- 打工人,從 JMM 透析 volatile 與 synchronized 原理synchronized
- volatile
- TCP與UDP區別詳解TCPUDP
- 詳解:Flannel安裝與配置
- Keepalived部署與配置詳解
- MongoDB索引與優化詳解MongoDB索引優化
- ActiveMQ基本詳解與總結MQ
- Proxy詳解,運用與Mobx
- LeakCanary詳解與原始碼分析原始碼
- nginx與location語法詳解Nginx
- MapReduce 詳解與原始碼分析原始碼