java并發(fā)編程中實現(xiàn)可見性的四種可行方案解析
在方法或者變量已經(jīng)同步的情況下,還會出現(xiàn)什么問題嗎?
多線程編程主要學的就是"互斥"和"可見","互斥"指的就是就是同步,而"可見"想必很多人還沒有理解.
舉個例子:
MyVolatile.java:
package cn.mxl.test.wr; public class MyVolatile { private int a=0; public void write() throws InterruptedException { a++; System.out.println("當前線程:"+Thread.currentThread().getName()); System.out.println(a); } public void read() throws InterruptedException { while(a==0) { // Thread.sleep(1); // System.out.println(a); } System.out.println("當前線程:"+Thread.currentThread().getName()); System.out.println(a); } }
MyRead.java:
package cn.mxl.test.wr; public class MyRead implements Runnable{ private MyVolatile task; public MyRead(MyVolatile task) { // TODO Auto-generated constructor stub this.task=task; } @Override public void run() { // TODO Auto-generated method stub try { task.read(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
MyWrite.java:
package cn.mxl.test.wr; public class MyWrite implements Runnable{ private MyVolatile task; public MyWrite(MyVolatile task) { // TODO Auto-generated constructor stub this.task=task; } @Override public void run() { // TODO Auto-generated method stub try { task.write(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
Run.java:
package cn.mxl.test.wr; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; public class Run { public static void main(String[] args) throws Exception, ExecutionException { MyVolatile task=new MyVolatile(); MyWrite mt1=new MyWrite(task); MyRead mt2=new MyRead(task); Thread tW=new Thread(mt1,"Write"); Thread tR=new Thread(mt2,"Read"); tR.start(); Thread.sleep(2000); tW.start(); } }
運行結果:
Read線程一直處于a==0中是為什么呢?
因為當Read線程 先開始線程的時候,加載主內(nèi)存中的數(shù)據(jù)放到自己的私有內(nèi)存中,在程序執(zhí)行過程中為了提高效率,它就只讀自己私有內(nèi)存中的數(shù)據(jù),不會再去讀主內(nèi)存中的共享數(shù)據(jù),在這個過程中,主內(nèi)存對于該線程來說,只寫不讀,也就是說將自己修改的變量值存放到主內(nèi)存中,但是自己不去讀主內(nèi)存的數(shù)據(jù);所以說,在Read線程執(zhí)行到while語句一直循環(huán)的時候,即使Write線程修改a==1值了,Read線程還是之前a==0的值,一直跳不出循環(huán);
解決辦法-->可見性,讓Read線程讀a變量的時候去主內(nèi)存(共享數(shù)據(jù))中讀取:
volatiel關鍵字的使用:
MyVolatile.java:
package cn.mxl.test.wr; public class MyVolatile { private volatile int a=0; public void write() throws InterruptedException { a++; System.out.println("當前線程:"+Thread.currentThread().getName()); System.out.println(a); } public void read() throws InterruptedException { while(a==0) { // Thread.sleep(1); // System.out.println(a); } System.out.println("當前線程:"+Thread.currentThread().getName()); System.out.println(a); } }
結果:
其實在這個過程中,我遇到了一些有趣的事情,可見性這東西,其實還有三個東西可以實現(xiàn):
第一個-->Thread.sleep():
MyVolatile.java(取消sleep的注解):
package cn.mxl.test.wr; public class MyVolatile { private int a=0; public void write() throws InterruptedException { a++; System.out.println("當前線程:"+Thread.currentThread().getName()); System.out.println(a); } public void read() throws InterruptedException { while(a==0) { Thread.sleep(1); // System.out.println(a); } System.out.println("當前線程:"+Thread.currentThread().getName()); System.out.println(a); } }
結果:
第二個是system.out.println():
MyVolatile.java:
package cn.mxl.test.wr; public class MyVolatile { private int a=0; public void write() throws InterruptedException { a++; System.out.println("當前線程:"+Thread.currentThread().getName()); System.out.println(a); } public void read() throws InterruptedException { while(a==0) { // Thread.sleep(1); System.out.println(a); } System.out.println("當前線程:"+Thread.currentThread().getName()); System.out.println(a); } }
結果:
第三個atomic:
MyVolatile.java:
package cn.mxl.test.wr.atomic; import java.util.concurrent.atomic.AtomicInteger; public class MyVolatile { private AtomicInteger a=new AtomicInteger(); public void write() throws InterruptedException { a.incrementAndGet(); System.out.println("當前線程:"+Thread.currentThread().getName()); System.out.println(a); } public void read() throws InterruptedException { while(a.get()==0) { // Thread.sleep(1); // System.out.println(a); } System.out.println("當前線程:"+Thread.currentThread().getName()); System.out.println(a); } }
結果:
到此這篇關于java并發(fā)編程中實現(xiàn)可見性的四種可行方案解析的文章就介紹到這了,更多相關java實現(xiàn)可見性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java中IO流使用FileWriter寫數(shù)據(jù)基本操作詳解
這篇文章主要介紹了Java中IO流FileWriter寫數(shù)據(jù)操作,FileWriter類提供了多種寫入字符的方法,包括寫入單個字符、寫入字符數(shù)組和寫入字符串等,它還提供了一些其他的方法,如刷新緩沖區(qū)、關閉文件等,需要的朋友可以參考下2023-10-10Java遠程執(zhí)行shell命令出現(xiàn)java: command not found問題及解決
這篇文章主要介紹了Java遠程執(zhí)行shell命令出現(xiàn)java: command not found問題及解決方案,具有很好的參考價值,希望對大家有所幫助。2023-07-07Java中關于String StringBuffer StringBuilder特性深度解析
這篇文章主要介紹了Java中關于String StringBuffer StringBuilder特性深度解析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-09-09詳解springboot集成websocket的兩種實現(xiàn)方式
這篇文章主要介紹了springboot集成websocket的兩種實現(xiàn)方式,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01關于Spring?Cache?緩存攔截器(?CacheInterceptor)
這篇文章主要介紹了關于Spring?Cache緩存攔截器(?CacheInterceptor),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12