java并发编程中实现可见性的四种可行方案解析
在方法或者变量已经同步的情况下,还会出现什么问题吗?
多线程编程主要学的就是"互斥"和"可见","互斥"指的就是就是同步,而"可见"想必很多人还没有理解.
举个例子:
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线程 先开始线程的时候,加载主内存中的数据放到自己的私有内存中,在程序执行过程中为了提高效率,它就只读自己私有内存中的数据,不会再去读主内存中的共享数据,在这个过程中,主内存对于该线程来说,只写不读,也就是说将自己修改的变量值存放到主内存中,但是自己不去读主内存的数据;所以说,在Read线程执行到while语句一直循环的时候,即使Write线程修改a==1值了,Read线程还是之前a==0的值,一直跳不出循环;
解决办法-->可见性,让Read线程读a变量的时候去主内存(共享数据)中读取:
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); } }
结果:
其实在这个过程中,我遇到了一些有趣的事情,可见性这东西,其实还有三个东西可以实现:
第一个-->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并发编程中实现可见性的四种可行方案解析的文章就介绍到这了,更多相关java实现可见性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
SpringBoot集成swagger-ui以及swagger分组显示操作
这篇文章主要介绍了SpringBoot集成swagger-ui以及swagger分组显示操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2020-09-09Spring boot使用logback实现日志管理过程详解
这篇文章主要介绍了Spring boot使用logback实现日志管理过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2020-06-06MyBatis-Plus updateById不更新null值的方法解决
用Mybatis-Plus的updateById()来更新数据时,无法将字段设置为null值,更新后数据还是原来的值,本文就来详细的介绍一下解决方法,具有一定的参考价值,感兴趣的可以了解一下2023-08-08SpringBoot中@ConfigurationProperties 配置绑定
本文主要介绍了SpringBoot中@ConfigurationProperties 配置绑定,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下2021-11-11
最新评论