`

线程安全扫盲贴三——共享实例(Sharing Objects)

 
阅读更多

       前面说了如何管理对共享、易变状态的数据的状态的访问,《JAVA并发编程》第三章主要介绍共享和发布可以被多线程安全访问的对象,使用了java.util.concurrent包下的类为基础,创建线程安全的类和构建安全的并发应用程序。

           synchronized不仅仅与操作原子性和关键区域定界相关,它还有个重要却不明显的作用——内存可见性。同步不仅仅是防止线程修改正在被别的线程使用的对象状态,还可以保证当一个线程修改了对象状态后,其他线程可以看到状态的更新。通过显示的同步或利用内置的同步的类库,可以保证发布的对象是线程安全的。

 

可见性

      当一个线程对对象状态进行读操作,另一个线程对该对象状态进行写操作时,如果没有线程同步,则无法保证读对象的线程能即时的读取到写对象更新后的值。

 

package com.zyp.test.concurrent;

public class NoVisibility {
	private static boolean ready;//默认值为false
	private static int number;

	private static class ReaderThread extends Thread {
		public void run() {
			while (!ready)
				Thread.yield();
			System.out.println(number);
		}
	}

	public static void main(String[] args) {
		new ReaderThread().start();
		number = 42;
		ready = true;
		System.out.println("end");
	}
}

这段代码中有两个线程,一个主线程和一个读线程都要反问number和ready。主线程启动读线程后,将ready置为true。读线程一直循环,直到发现ready为true后,打印number的值。看起来读线程打印结果:
1:可能是明显的42,

2:也可能打印出0,

3:也可能永远不停止。

因为没有适当的同步,不能保证主线程写了number和ready一定对读线程是可见的。上面读线程可能永远不停止,因为ready可能对读线程永远不可见。上面可能打印出0,跟重排序有关。

重排序(reordering):在一个线程中的方法的执行顺序并不保证与代码中顺序一致。在没有同步的情况下,java内存模型(JMM)允许编译器重新排序操作,以获取多处理器带来的更多好处。

重排序后,编译器后的代码可能先执行ready的赋值再执行number的赋值。

 

 

 

分享到:
评论
1 楼 fantasy 2013-03-13  
写得不错 加油!

相关推荐

Global site tag (gtag.js) - Google Analytics