在java.util.concurrent包里包含的主要就是一些与并发实现相关的类,首先来看一下最为基础的原子类(java.util.concurrent.atomic)和和线程锁(java.utl.concurrent.locks)。这一篇将着重讲解一下原子类。
在java.util.concurrent.atomic中都是一些命名形式为Atomic*的类,如AtomicInteger、AtomicLong等,拿Atomic举例来说,调用类中相关的方法可以肯定,能够返回一个唯一的数值。在这个类中有一个关键的变量定义如下:
private volatile int value;这个私有的变量被volatile修饰,那么volatile关键字的作用是什么呢?
(2)线程在获取value值时,这个值必须要从主内存中取出
可以看到,其实被volatile修饰的原始类型类似于一个小小的同步块,但是与同步块比起来,由于没有线程锁这样一个概念,所以在某些情况下还是得不到保证。例如要获取一个唯一增长的序列时,还是会产生问题。
举个例子:
public class UnsafeSequence { private volatile int value; public int get() { return value++; } }在执行的时候,两个线程在调用get()方法时很可能会得到相同的值。如何能保证一个唯一且增长的序列时,可能会给get()方法上锁(加synchronized关键字或同步块),这时候就不需要volatile关键字了,因为如果给get()方法上锁,那么同步块本身会刷内存的。怎么利用volatile来实现呢?
下面继续来分析源码,发现这个类中提供了一些设置value值的方法,其中就包括对value值进行加1的操作,如下:
public final int getAndIncrement() { for (;;) { int current = get(); // 获取value当前值 int next = current + 1; if (compareAndSet(current, next)) return current; } }还有comareAndSet()方法的源代码如下:
/** * Atomically sets the value to the given updated value * if the current value == the expected value. */ public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
当value值等于expect的时候,修改value的值为update,也就是给value值加1。可能有些人会问,为什么要比较value和expect的值呢?这就是设计的巧妙之处。
试想一下,如果value值为2的时候,被两个线程调用get()方法得到值后,其中线程1为value值加1后,调用compareAndSet()方法将value值修改为3并被刷回到内存中。线程2也要调用compareAndSet()方法时,这时的expect=2就和value=3的值不符合了,所以不会返回3,避免错误。
此时如何处理呢?在for(;;)死循环中重新作处理后,就可以得到正确的值4并且返回了。
下面我们来利用这个类得到 一个唯一且完全增长的序列,如下:
public class SafeSequence { private final AtomicInteger value=new AtomicInteger(0); public int getSequence() { return value.getAndIncrement(); } }
原文:http://blog.csdn.net/mazhimazh/article/details/18908493