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);
	}
}

结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值