2015年3月11日

来源:互联网 发布:做动画用什么软件 编辑:程序博客网 时间:2024/05/01 08:12

Atomic 类概述

  java为什么会引入Atomic类的包呢?atomic类在java.util.concurrent包下面,可以知晓,该类的出现是与安全相关的,当我们对一个int类型的变量进行操作的时候,有可能会遇到线程安全的问题,我们可以先看一个用例,笔者自己并没能实验出来,该用例来源于文章,http://blog.csdn.net/a19881029/article/details/8202933 

public class SCounter {private static int count;public void add() {System.out.println(Thread.currentThread().getName() + ":" + (count++));}public static void main(String[] args) {final SCounter sc = new SCounter();Runnable task1 = new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubsc.add();}};ExecutorService es = Executors.newCachedThreadPool();for (int i = 0; i < 5; i++) {es.submit(task1);}es.shutdown();}}

其运行结果为:

pool-1-thread-2:0pool-1-thread-5:3pool-1-thread-1:2pool-1-thread-3:1pool-1-thread-4:4

偶尔会有:

pool-1-thread-2:0pool-1-thread-5:3pool-1-thread-1:2pool-1-thread-3:1pool-1-thread-4:3

位什么会有这个情况发生呢?

是因为其中我们在执行代码count++的时候,虽然只有一句代码,但是jvm确分成了几个步骤来完成这一操作。

getstatic  获取指定类的静态域,并将其值压入栈顶  iconst_1   将int型1推送至栈顶  iadd       将栈顶两int型数值相加并将结果压入栈顶  dup        复制栈顶数值并将复制值压入栈顶  putstatic  为指定类的静态域赋值 

如果在有个线程在执行这5个步骤的过程中被打断了,那么就会出现上述安全问题。

2,atomic类的工作原理。

而atomic包里面提供了对一些基本类型的封装类比如说AtomicInteger,AtomicLong 等等,提供了一些机制,来确保最后被修改的值的安全性。

那么Atomic类是如何来确保其最后修改的值的正确性呢?在处理该问题之前,我们需要分清3个变量的值,expectValue---我们所期望我们的更改基于该值的。ActuralValue--实际当前内存地址上的值,newValue我们期望的更改之后新的值

拿atomicInteger的getAndSet方法来举例,其源码为:

  public final int getAndSet(int newValue) {        for (;;) {            int current = get();            if (compareAndSet(current, newValue))                return current;        }    }

 public final boolean compareAndSet(int expect, int update) {        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);    }

Unsafe的对象中compareAndSwapInt方法:

public final native boolean compareAndSwapInt(Object o, long offset,                                                      int expected,                                                      int x);

sun::misc::Unsafe::compareAndSwapInt (jobject obj, jlong offset,  jint expect, jint update)  {  jint *addr = (jint *)((char *)obj + offset);  return compareAndSwap (addr, expect, update);  }

compareAndSwap (volatile jint *addr, jint old, jint new_val)  {  jboolean result = false;  spinlock lock;  if ((result = (*addr == old)))  *addr = new_val;  return result;  }

可以看见,atomicInteger 的getAndSet方法里面有一个for循环,该循环会不断的尝试和确认,我们当前的操作是否基于内存中最新的值,如果不是的话,就重新从内存中读取该值,并且把我们的需要更改的值添加上去。

从而来确保,无论任何时候,对于Integer的操作,都是正确的。


0 0
原创粉丝点击