7.使用原子变量
说明:原子变量(Atomic Variable): 提供了单个变量上的原子操作。在编译程序时,
java代码中的每个变量,每个操作都将被转换成机器可以理解的指令。
例如,当给一个变量赋值时,在java代码中只使用一个指令,
但是编译这个程序时,指令被转换成JVM语言的不同指令。
当多个线程共享同一个变量时,就会发生数据不一致的错误,java中引入原子变量来避免该类错误。
当一个线程在堆原子变量操作时,如果其他线程也试图对同一原子变量执行操作,
原子变量提供了一套机制来检查操作是否在一步之内完成。
这种操作就是CAS原子操作(Compare And Set).就是说先获取变量的值,
然后在本地改变变量的值,然后试图用这个改变的值去替换之前的值,
如果之前的 值没有被其他线程改变就可以执行这个操作,否则,方法将再执行这个操作。
。
原子变量不使用锁或者其他同步机制来保护对其值的并发访问。所有操作都是基于CAS原子操作的。
它保证了多线程在同一时间操作一个原子变量而不会产生数据不一致的错误,性能优于使用同步
机制保护的普通变量。但是这种机制会引起ABA问题,
本范例使用AtomicLong类
java还提供了其他原子类:AtomicBoolean
AtomicInteger 和AtomicReference是原子类的其他实现类。
本案例继续模拟银行操作,由于本书中有众多实际生活中的案例,生产者消费者模型,银行ATM存取款模型,在第7章结束后关于本书的内容会继续总结下去。敬请期待。。。
实例代码:
/**
*
* @author fcs
* @date 2015-6-22
* 描述:使用原子变量
* 说明:使用原子变量模拟银行存取款模型
*/
public class Acount {
private AtomicLong balence;
public Acount() {
balence = new AtomicLong();
}
public AtomicLong getBalence() {
return balence;
}
public void setBalence(AtomicLong balence) {
this.balence = balence;
}
//增加balence存款
public void addBalence(long amount){
this.balence.getAndAdd(amount);
}
//减少balence存款
public void subBalence(long amount){
this.balence.getAndAdd(- amount);
}
}
/**
*
* @author fcs
* @date 2015-6-22
* 描述:模拟从账户取款
* 说明:
*/
public class Bank implements Runnable{
private Acount acount ;
public Bank(Acount acount) {
this.acount = acount;
}
@Override
public void run() {
for(int i =0 ;i< 1000000;i++){
acount.addBalence(1000);
}
}
}
/**
*
* @author fcs
* @date 2015-6-22
* 描述:模拟公司存款
* 说明:
*/
public class Company implements Runnable {
private Acount acount;
public Company(Acount acount) {
this.acount = acount;
}
@Override
public void run() {
for(int i =0;i< 1000000;i++){
acount.subBalence(1000);
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}