java并发编程中实现可见性的四种可行方案解析
作者:键盘林
这篇文章主要介绍了java并发编程中实现可见性的四种可行方案解析,使用关键字volatile和使用锁(如synchronized关键字或者java.util.concurrent包中的锁)来确保对共享变量的修改在多线程环境中能够正确地被其他线程所观察到,需要的朋友可以参考下
在方法或者变量已经同步的情况下,还会出现什么问题吗?
多线程编程主要学的就是"互斥"和"可见","互斥"指的就是就是同步,而"可见"想必很多人还没有理解.
举个例子:
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实现可见性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
