从相对简单的Atomic入手(java.util.concurrent是基于Queue的并发包,而Queue,很多情况下使用到了Atomic操作,因此首先从这里开始)。很多情况下我们只是需要一个简单的、高效的、线程安全的递增递减方案。注意,这里有三个条件:简单,意味着程序员尽可能少的操作底层或者实现起来要比较容易;高效意味着耗用资源要少,程序处理速度要快;线程安全也非常重要,这个在多线程下能保证数据的正确性。这三个条件看起来比较简单,但是实现起来却难以令人满意。

通常情况下,在Java里面,++i或者--i不是线程安全的,这里面有三个独立的操作:或者变量当前值,为该值+1/-1,然后写回新的值。在没有额外资源可以利用的情况下,只能使用加锁才能保证读-改-写这三个操作时“原子性”的。

Doug Lea在未将backport-util-concurrent合并到JSR 166里面来之前,是采用纯Java实现的,于是不可避免的采用了synchronized关键字。

public final synchronized void set(int newValue);

public final synchronized int getAndSet(int newValue);

public final synchronized int incrementAndGet();

同时在变量上使用了volatile (后面会具体来讲volatile到底是个什么东东)来保证get()的时候不用加锁。尽管synchronized的代价还是很高的,但是在没有JNI的手段下纯Java语言还是不能实现此操作的。

JSR 166提上日程后,backport-util-concurrent就合并到JDK 5.0里面了,在这里面重复使用了现代CPU的特性来降低锁的消耗。后本章的最后小结中会谈到这些原理和特性。在此之前先看看API的使用。

一切从java.util.concurrent.atomic.AtomicInteger开始。

int addAndGet(int delta)
          以原子方式将给定值与当前值相加。 实际上就是等于线程安全版本的i =i+delta操作。

boolean compareAndSet(int expect, int update)
          如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。 如果成功就返回true,否则返回false,并且不修改原值。

int decrementAndGet()
          以原子方式将当前值减 1。 相当于线程安全版本的--i操作。

int get()
          获取当前值。

int getAndAdd(int delta)
          以原子方式将给定值与当前值相加。 相当于线程安全版本的t=i;i+=delta;return t;操作。

int getAndDecrement()
          以原子方式将当前值减 1。 相当于线程安全版本的i--操作。

int getAndIncrement()
          以原子方式将当前值加 1。 相当于线程安全版本的i++操作。

int getAndSet(int newValue)
          以原子方式设置为给定值,并返回旧值。 相当于线程安全版本的t=i;i=newValue;return t;操作。

int incrementAndGet()
          以原子方式将当前值加 1。 相当于线程安全版本的++i操作。

void lazySet(int newValue)
          最后设置为给定值。 延时设置变量值,这个等价于set()方法,但是由于字段是volatile类型的,因此次字段的修改会比普通字段(非volatile字段)有稍微的性能延时(尽管可以忽略),所以如果不是想立即读取设置的新值,允许在“后台”修改值,那么此方法就很有用。如果还是难以理解,这里就类似于启动一个后台线程如执行修改新值的任务,原线程就不等待修改结果立即返回(这种解释其实是不正确的,但是可以这么理解)。

void set(int newValue)
          设置为给定值。 直接修改原始值,也就是i=newValue操作。

boolean weakCompareAndSet(int expect, int update)
          如果当前值 == 预期值,则以原子方式将该设置为给定的更新值。JSR规范中说:以原子方式读取和有条件地写入变量但 创建任何 happen-before 排序,因此不提供与除 weakCompareAndSet 目标外任何变量以前或后续读取或写入操作有关的任何保证。大意就是说调用weakCompareAndSet时并不能保证不存在happen-before的发生(也就是可能存在指令重排序导致此操作失败)。但是从Java源码来看,其实此方法并没有实现JSR规范的要求,最后效果和compareAndSet是等效的,都调用了unsafe.compareAndSwapInt()完成操作。

下面的代码是一个测试样例,为了省事就写在一个方法里面来了。

package xylz.study.concurrency.atomic;

import java.util.concurrent.atomic.AtomicInteger;

import org.junit.Test;

import static org.junit.Assert.*;

public class AtomicIntegerTest {

    @Test
    public void testAll() throws InterruptedException{
        final AtomicInteger value = new AtomicInteger(10);
        assertEquals(value.compareAndSet(1, 2), false);
        assertEquals(value.get(), 10);
        assertTrue(value.compareAndSet(10, 3));
        assertEquals(value.get(), 3);
        value.set(0);
        //
        assertEquals(value.incrementAndGet(), 1);
        assertEquals(value.getAndAdd(2),1);
        assertEquals(value.getAndSet(5),3);
        assertEquals(value.get(),5);
        //
        final int threadSize = 10;
        Thread[] ts = new Thread[threadSize];
        for (int i = 0; i < threadSize; i++) {
            ts[i] = new Thread() {
                public void run() {
                    value.incrementAndGet();
                }
            };
        }
        //
        for(Thread t:ts) {
            t.start();
        }
        for(Thread t:ts) {
            t.join();
        }
        //
        assertEquals(value.get(), 5+threadSize);
    }

}

由于这里例子比较简单,这里就不做过多介绍了。
AtomicInteger和AtomicLong、AtomicBoolean、AtomicReference差不多,这里就不介绍了。在下一篇中就介绍下数组、字段等其他方面的原子操作。
 参考资料:
(1)http://stackoverflow.com/questions/2443239/java-atomicinteger-what-are-the-differences-between-compareandset-and-weakcompar
(2)http://stackoverflow.com/questions/1468007/atomicinteger-lazyset-and-set

深入浅出 Java Concurrency (2): 原子操作 part 1[转]的更多相关文章

  1. 深入浅出 Java Concurrency (4): 原子操作 part 3 指令重排序与happens-before法则

    转: http://www.blogjava.net/xylz/archive/2010/07/03/325168.html 在这个小结里面重点讨论原子操作的原理和设计思想. 由于在下一个章节中会谈到 ...

  2. 《深入浅出 Java Concurrency》——原子操作

    part1 从AtomicInteger開始 从相对简单的Atomic入手(java.util.concurrent是基于Queue的并发包.而Queue.非常多情况下使用到了Atomic操作.因此首 ...

  3. 深入浅出 Java Concurrency (4): 原子操作 part 3 指令重排序与happens-before法则[转]

    在这个小结里面重点讨论原子操作的原理和设计思想. 由于在下一个章节中会谈到锁机制,因此此小节中会适当引入锁的概念. 在Java Concurrency in Practice中是这样定义线程安全的: ...

  4. 深入浅出 Java Concurrency (3): 原子操作 part 2

    转:http://www.blogjava.net/xylz/archive/2010/07/02/325079.html 在这一部分开始讨论数组原子操作和一些其他的原子操作. AtomicInteg ...

  5. 深入浅出 Java Concurrency (2): 原子操作 part 1

    转:http://www.blogjava.net/xylz/archive/2010/07/01/324988.html 从相对简单的Atomic入手(java.util.concurrent是基于 ...

  6. 深入浅出 Java Concurrency (3): 原子操作 part 2[转]

    在这一部分开始讨论数组原子操作和一些其他的原子操作. AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray的API类似,选择有代表性的Atom ...

  7. 深入浅出 Java Concurrency (5): 原子操作 part 4 CAS操作

    在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁(后面的章节还会谈到锁). 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度 ...

  8. 深入浅出 Java Concurrency (5): 原子操作 part 4[转]

    在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁(后面的章节还会谈到锁). 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度 ...

  9. 深入浅出 Java Concurrency (15): 锁机制 part 10 锁的一些其它问题

      主要谈谈锁的性能以及其它一些理论知识,内容主要的出处是<Java Concurrency in Practice>,结合自己的理解和实际应用对锁机制进行一个小小的总结. 首先需要强调的 ...

随机推荐

  1. bzoj 1196: [HNOI2006]公路修建问题(二分+贪心)

    传送门 解题思路 看到最大,肯定要先想二分答案.二分之后首先从小到大枚举\(k\)个小于\(lim\)的所有一级公路,然后用并查集连到一起,然后就在剩下的里面从小到大找n-1-k个二级公路,模仿最小生 ...

  2. SpringBoot_05_ssm拦截器和默认欢迎页面的设置

    1.在springBoot下通过使用拦截器完成在没有登陆的前提下,不允许访问其他资源 编写拦截器,要实现HandlerInterceptor @Component public class UserI ...

  3. pycharm for mac安装

    http://www.xue51.com/mac/5604.html

  4. layui之input里格式验证

    form.verify({          title: function(value){            if(value.length < 5){              retu ...

  5. 使用virtualenv发布Python程序

    客户环境不能上网,开始想把所有依赖包下载下来,进入客户环境进行安装.但为了避免出差,部署工作交给其他同事了,我想还是需要更简单的方式. 实验了一下virtualenv是可以的 1. 创建一个新的环境( ...

  6. 判断语句(if...else)if...else语句是在指定的条件成立时执行代码,在条件不成立时执行else后的代码

    判断语句(if...else) if...else语句是在指定的条件成立时执行代码,在条件不成立时执行else后的代码. 语法: if(条件) { 条件成立时执行的代码 } else { 条件不成立时 ...

  7. Echart使用过的属性总结

    改变坐标轴颜色与粗细: axisLine: { lineStyle: {//设置轴的颜色 color: '#CD0000', width: 1,//轴的宽度 } } 改变坐标轴上刻度的间隔与倾斜方向: ...

  8. cycloneii normal mode vs. arithmetic mode

    Combout = F(data1, data2, data3 or cin, data4) 在 arithmetic mode,只有 data1\data2 参加运算. 4-LUT到2个3-LUT的 ...

  9. [JZOJ4633] 【GDOI2017模拟7.15】萌萌哒

    题目 描述 题目大意 给你一个数列,接下来有许多个操作,使得区间[l1,r1][l_1,r_1][l1​,r1​]和[l2,r2][l_2,r_2][l2​,r2​]对应的位置染上同样的颜色(使得它们 ...

  10. csp-s模拟65Simple,Walk, Travel,棋盘题解

    题面:https://www.cnblogs.com/Juve/articles/11639923.html simple: 考试时只想到的暴力exgcd判断 考虑n,m互质的情况: 我们枚举y,对于 ...