同步机制可以保证原子操作和内存可见性,但是同步机制对变量的访问性能是我们不得不考虑的问题,java语言提供了一种弱同步机制,volatile变量。
它的原理大致是这样的,当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量总会返回最新写入的值。(参考《java并发编程实践》一书)
让我们来看一个实例:
package com.home.thread; /** * @author gaoxu * */ public class ThreadStart { private static class ReaderThread extends Thread{ public void run(){ SafeThread.setNumber(1); } } private static class ReaderThread1 extends Thread{ public void run(){ long start = System.currentTimeMillis(); System.out.println("="+SafeThread.getNumber()); long endTime = System.currentTimeMillis()-start; System.out.println("所用时间:"+endTime); } } public static void main(String[] para){ new ReaderThread().start(); new ReaderThread1().start(); } }
package com.home.thread; import java.util.concurrent.atomic.AtomicInteger; /** * @author gaoxu * */ public class SafeThread { volatile static int number; public static int getNumber() { return number; } public static void setNumber(int number) { SafeThread.number = number; } }
这段代码的运行结果是 1 ,也就是说getNumber保证获取到的都是number变量最新的内存值,这都是volatile的功劳,我们可以把对volatile变量的访问想象成是synchronized的set和get操作(虽然同步远比volatile的内存可见性强),volatile的使用看似很方便,但是它的使用是有局限性的。
volatile变量的使用只能保证变量的内存可见性,不能保证变量的原子性,所以volatile变量的使用有如下条件:
对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。
该变量不会与其他的状态变量一起纳入不变条件中。
在访问变量时不需要加锁。
我们看到上面代码的例子完全符合他的这些条件,所以这个例子是完全可以使用volatile的。
另外我们也在代码中加了测试时间的代码:
每种方式运行10遍。
得出的结论是使用volatile变量比同步平均快1毫秒。(精确度不高)
时间: 2024-10-12 13:40:35