多线程学习(八)

原子性和易变性

要理解黄色标注的内容那得 了解一下java中的内存模型:

Java内存模型FAQ : http://ifeve.com/jmm-faq/
同步和java内存模型: http://ifeve.com/syn-jmm/
java内存模型指南: http://ifeve.com/jmm-cookbook/
深入理解java内存模型: http://ifeve.com/java-memory-model-0/

首先看完java内存模型我们了解到:java线程运行时分主存和线程的工作内存,线程的工作内存(相当于是缓存)会有主存的共享变量的副本,所有的修改和读取都是针对于线程的工作线程的。其实工作线程只是一个抽象的概念不一定存在

看完这个你可能会有一点疑问?既然所有的线程读取和修改都是针对工作线程 那么他就应该是线程安全的啊 因为各个线程工作内存各自不影响啊!其实

public class IntGeneratorActual extends IntGenerator {
	private int val = 0;

	@Override
	public int next() {
		System.out.println("Thread:" + Thread.currentThread().getName() + " read val:" + val);
		val++;
		System.out.println("Thread:" + Thread.currentThread().getName() + " yield before:" + val);
		Thread.yield();
		System.out.println("Thread:" + Thread.currentThread().getName() + " yield  after:" + val);
		val++;
		return val;
	}

	public int getVal() {
		return val;
	}
}
public class EvenChecker2 implements Runnable {
	private IntGeneratorActual actual;

	public EvenChecker2(IntGeneratorActual actual) {
		super();
		this.actual = actual;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			int a = actual.getVal();
			if (a % 2 != 0) {
				System.out.println("get not steady val:" + a);
				actual.cancel();
				break;
			}
		}
	}

}
public class JMMTest1 implements Runnable {
	private IntGeneratorActual intGeneratorActual;

	public JMMTest1(IntGeneratorActual intGeneratorActual) {
		super();
		this.intGeneratorActual = intGeneratorActual;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (!intGeneratorActual.isCanceled()) {
			int a = intGeneratorActual.next();
			System.out.println("Thread:"+Thread.currentThread().getName()+" next:"+a);
		}

	}

	public static void main(String[] args) {
		ExecutorService executorService = Executors.newFixedThreadPool(5);
		IntGeneratorActual actual = new IntGeneratorActual();
		Runnable target = new JMMTest1(actual);
		Runnable target2 = new EvenChecker2(actual);
		for (int i = 0; i < 4; i++) {
			executorService.execute(target);

		}
		executorService.execute(target2);
		executorService.shutdown();
	}
}

根据输出可以看出,你根本不知道 缓存什么时候会把 值写进 主存,也不知道什么时候 线程会读取主存中的值。你根本不知道线程的工作线程是否存在。(本人能力有限是在理解不了这一些).
我总结如下:线程原子性的问题的时候就当没有线程的工作内存 所有的操作都像是直接针对主存
线程可见性的问题的时候 是由于重排序导致的

posted @ 2017-05-07 17:58  风中小蘑菇  阅读(170)  评论(0编辑  收藏  举报