java多線程Synchronized實(shí)現(xiàn)可見性原理解析
Synchronized實(shí)現(xiàn)可見性原理
可見性
要實(shí)現(xiàn)共享變量的可見性,必須保證兩點(diǎn):
- 線程修改后的共享變量值能夠及時(shí)從工作內(nèi)存刷新到主內(nèi)存中
- 其他線程能夠及時(shí)把共享變量的最新值從主內(nèi)存更新到自己的工作內(nèi)存中
Java語言層面支持的可見性的實(shí)現(xiàn)方式
- synchronized
- volatile
synchronized實(shí)現(xiàn)可見性
synchronized能夠?qū)崿F(xiàn):
- 原子性(同步)
- 可見性
JMM關(guān)于synchronized的兩條規(guī)定:
- 1.線程解鎖前,必須把貢獻(xiàn)變量的最新值刷新到主內(nèi)存中
- ?2.線程加鎖時(shí),將清空工作內(nèi)存中共享變量的值,從而使用共享變量時(shí)需要從主內(nèi)存中重新讀取最新的值(注意:加鎖與解鎖需要同一把鎖)
線程解鎖前對共享變量的修改在下次加鎖時(shí)對其他線程可見
線程執(zhí)行互斥代碼的過程
- 獲取互斥鎖
- 清空工作內(nèi)存
- 從主內(nèi)存拷貝變量的最新副本到工作內(nèi)存
- 執(zhí)行代碼
- 將更改后的共享變量的值刷新到主內(nèi)存
- 釋放互斥鎖
重排序:
代碼書寫的順序與實(shí)際執(zhí)行的順序不同,指令重排序是編譯器或處理器為了提高程序性能而做得優(yōu)化
- 編譯器優(yōu)化的重排序(編譯器優(yōu)化)
- 指令級并行重排序(處理器優(yōu)化)
- 內(nèi)存系統(tǒng)的重排序(處理器優(yōu)化)
as-if-serial
as-if-serial:無論如何重排序,程序執(zhí)行的結(jié)果應(yīng)該與代碼順序執(zhí)行的結(jié)果一致(Java編譯器、運(yùn)行時(shí)和處理器都會(huì)保證Java在單線程下遵循as-if-serial語義)

public class SynchronizedTest {
/**
* 共享變量
*/
private boolean ready = false;
private int result = 0;
private int number = 1;
/**
* 寫操作
*/
public void write(){
ready = true;//1.1
number = 2;//1.2
}
/**
* 讀操作
*/
public void read(){
if(ready){//2.1
result=number*3;//2.2
}
System.out.println("result的值為:"+result);
}
/**
* 內(nèi)部線程類
*/
private class ReadWriteThread extends Thread{
//根據(jù)構(gòu)造方法中傳入的flag參數(shù),確定線程執(zhí)行讀操作還是寫操作
private boolean flag;
public ReadWriteThread(boolean flag){
this.flag=flag;
}
@Override
public void run() {
if(flag){
//構(gòu)造方法中傳入true,執(zhí)行寫操作
write();
}else{
//構(gòu)造方法中傳入false,執(zhí)行讀操作
read();
}
}
}
public static void main(String[] args) {
SynchronizedTest synchronizedTest = new SynchronizedTest();
//啟動(dòng)線程執(zhí)行寫操作
synchronizedTest.new ReadWriteThread(true).start();
//啟動(dòng)線程執(zhí)行讀操作
synchronizedTest.new ReadWriteThread(false).start();
}
}
導(dǎo)致共享變量在線程間不可見的原因
1.線程的交叉執(zhí)行
eg:上述程序執(zhí)行步驟為1.1-》2.1-》2.2-》1.2

eg:上述程序執(zhí)行步驟為1.2-》2.1-》2.2-》1.1

2.重排序結(jié)合線程交叉執(zhí)行
eg: 2.1和2.2重排序后
int mid = number*3;
if(ready){
result=mid;
}
共享變量更新后的值沒有在工作內(nèi)存與主內(nèi)存間及時(shí)更新
安全性代碼
public class SynchronizedTest {
/**
* 共享變量
*/
private boolean ready = false;
private int result = 0;
private int number = 1;
/**
* 寫操作
*/
public synchronized void write(){
ready = true;//1.1
number = 2;//1.2
}
/**
* 讀操作
*/
public synchronized void read(){
if(ready){//2.1
result=number*3;//2.2
}
System.out.println("result的值為:"+result);
}
/**
* 內(nèi)部線程類
*/
private class ReadWriteThread extends Thread{
//根據(jù)構(gòu)造方法中傳入的flag參數(shù),確定線程執(zhí)行讀操作還是寫操作
private boolean flag;
public ReadWriteThread(boolean flag){
this.flag=flag;
}
@Override
public void run() {
if(flag){
//構(gòu)造方法中傳入true,執(zhí)行寫操作
write();
}else{
//構(gòu)造方法中傳入false,執(zhí)行讀操作
read();
}
}
}
public static void main(String[] args) {
SynchronizedTest synchronizedTest = new SynchronizedTest();
//啟動(dòng)線程執(zhí)行寫操作
synchronizedTest.new ReadWriteThread(true).start();
//啟動(dòng)線程執(zhí)行讀操作
synchronizedTest.new ReadWriteThread(false).start();
}
}

到此這篇關(guān)于java多線程Synchronized實(shí)現(xiàn)可見性原理的文章就介紹到這了,更多相關(guān)java多線程Synchronized內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
哈希表在算法題目中的實(shí)際應(yīng)用詳解(Java)
散列表(Hash?table,也叫哈希表)是根據(jù)關(guān)鍵碼值(Key?value)而直接進(jìn)行訪問的數(shù)據(jù)結(jié)構(gòu),下面這篇文章主要給大家介紹了關(guān)于哈希表在算法題目中的實(shí)際應(yīng)用,文中介紹的方法是Java,需要的朋友可以參考下2024-03-03
java實(shí)現(xiàn)table添加右鍵點(diǎn)擊事件監(jiān)聽操作示例
這篇文章主要介紹了java實(shí)現(xiàn)table添加右鍵點(diǎn)擊事件監(jiān)聽操作,結(jié)合實(shí)例形式分析了Java添加及使用事件監(jiān)聽相關(guān)操作技巧,需要的朋友可以參考下2018-07-07
Mybatis中#{}和${}傳參的區(qū)別及#和$的區(qū)別小結(jié)
這篇文章主要介紹了Mybatis中#{}和${}傳參的區(qū)別及#和$的區(qū)別小結(jié) 的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
Redis 訂閱發(fā)布_Jedis實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄猂edis 訂閱發(fā)布_Jedis實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06
spring boot 即時(shí)重新啟動(dòng)(熱更替)使用說明
這篇文章主要介紹了spring boot 即時(shí)重新啟動(dòng)(熱更替)的相關(guān)資料,需要的朋友可以參考下2017-12-12

