在这一部分开始讨论数组原子操作和一些其他的原子操作。

AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray的API类似,选择有代表性的AtomicIntegerArray来描述这些问题。

int get(int i)

获取位置 i 的当前值。很显然,由于这个是数组操作,就有索引越界的问题(IndexOutOfBoundsException异常)。

对于下面的API起始和AtomicInteger是类似的,这种通过方法、参数的名称就能够得到函数意义的写法是非常值得称赞的。在《重构:改善既有代码的设计》和《代码整洁之道》中都非常推崇这种做法。

void set(int i, int newValue)
void lazySet(int i, int newValue)
int getAndSet(int i, int newValue)
boolean compareAndSet(int i, int expect, int update)
boolean weakCompareAndSet(int i, int expect, int update)
int getAndIncrement(int i)
int getAndDecrement(int i)
int getAndAdd(int i, int delta)
int incrementAndGet(int i)
int decrementAndGet(int i)
int addAndGet(int i, int delta)

整体来说,数组的原子操作在理解上还是相对比较容易的,这些API就是有多使用才能体会到它们的好处,而不仅仅是停留在理论阶段。

现在关注字段的原子更新。

AtomicIntegerFieldUpdater<T>/AtomicLongFieldUpdater<T>/AtomicReferenceFieldUpdater<T,V>是基于反射的原子更新字段的值。

相应的API也是非常简单的,但是也是有一些约束的。

(1)字段必须是volatile类型的!在后面的章节中会详细说明为什么必须是volatile,volatile到底是个什么东西。

(2)字段的描述类型(修饰符public/protected/default/private)是与调用者与操作对象字段的关系一致。也就是说调用者能够直接操作对象字段,那么就可以反射进行原子操作。但是对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。

(3)只能是实例变量,不能是类变量,也就是说不能加static关键字。

(4)只能是可修改变量,不能使final变量,因为final的语义就是不可修改。实际上final的语义和volatile是有冲突的,这两个关键字不能同时存在。

(5)对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段,不能修改其包装类型(Integer/Long)。如果要修改包装类型就需要使用AtomicReferenceFieldUpdater。

在下面的例子中描述了操作的方法。

package xylz.study.concurrency.atomic; 

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; 

public class AtomicIntegerFieldUpdaterDemo { 

   class DemoData{
       public volatile int value1 = 1;
       volatile int value2 = 2;
       protected volatile int value3 = 3;
       private volatile int value4 = 4;
   }
    AtomicIntegerFieldUpdater<DemoData> getUpdater(String fieldName) {
        return AtomicIntegerFieldUpdater.newUpdater(DemoData.class, fieldName);
    }
    void doit() {
        DemoData data = new DemoData();
        System.out.println("1 ==> "+getUpdater("value1").getAndSet(data, 10));
        System.out.println("3 ==> "+getUpdater("value2").incrementAndGet(data));
        System.out.println("2 ==> "+getUpdater("value3").decrementAndGet(data));
        System.out.println("true ==> "+getUpdater("value4").compareAndSet(data, 4, 5));
    }
    public static void main(String[] args) {
        AtomicIntegerFieldUpdaterDemo demo = new AtomicIntegerFieldUpdaterDemo();
        demo.doit();
    }
} 

在上面的例子中DemoData的字段value3/value4对于AtomicIntegerFieldUpdaterDemo类是不可见的,因此通过反射是不能直接修改其值的。

AtomicMarkableReference类描述的一个<Object,Boolean>的对,可以原子的修改Object或者Boolean的值,这种数据结构在一些缓存或者状态描述中比较有用。这种结构在单个或者同时修改Object/Boolean的时候能够有效的提高吞吐量。

AtomicStampedReference类维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。对比AtomicMarkableReference类的<Object,Boolean>,AtomicStampedReference维护的是一种类似<Object,int>的数据结构,其实就是对对象(引用)的一个并发计数。但是与AtomicInteger不同的是,此数据结构可以携带一个对象引用(Object),并且能够对此对象和计数同时进行原子操作。

在后面的章节中会提到“ABA问题”,而AtomicMarkableReference/AtomicStampedReference在解决“ABA问题”上很有用。

 

原子操作的使用大概就是这么多,大体来说还算是比较清晰的,在下一个章节中,将对象原子操作进行总结,重点介绍下原子操作的原理和设计思想。

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

  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 (2): 原子操作 part 1[转]

    从相对简单的Atomic入手(java.util.concurrent是基于Queue的并发包,而Queue,很多情况下使用到了Atomic操作,因此首先从这里开始).很多情况下我们只是需要一个简单的 ...

  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. node.js在ubuntu上和windows上的安装

    Ubuntu 上安装 Node.js Node.js 源码安装 以下部分我们将介绍在Ubuntu Linux下安装 Node.js . 其他的Linux系统,如Centos等类似如下安装步骤. 在 G ...

  2. 万恶之源-python介绍

    PATH OF PYTHON (生命短暂,我要学pythonヾ(◍°∇°◍)ノ゙) 一.Python介绍: 简史:Python诞生于1989年的圣诞节, 创始人为Guido van Rossum, 又 ...

  3. JAVA工具包_BeanUtils

    简介 大多数的java开发者通常在创建Java类的时候都会遵循JavaBean的命名模式,对类的属性生成getters方法和setters方法.通过调用相应的getXxx和setXxx方法,直接访问这 ...

  4. a标签 href触发及传值

    var d=document.getElementById("exportA");alert(d.href);d.href="${ctx}/templet/tEdasTe ...

  5. springcloud ribbon Finchley 版本,自定义算法

    引用上一个项目,在原有的基础上进行更改,添加springcloud的内荣. eureka-server 和上一个springcloud eureka的一样,没有改动. 添加cloud-api pack ...

  6. Java开发系列-文件上传

    概述 Java开发中文件上传的方式有很多,常见的有servlet3.0.common-fileUpload.框架.不管哪种方式,对于文件上传的本质是不变的. 文件上传的准备 文件上传需要客户端跟服务都 ...

  7. MATLAB 去掉数组里面不要的元素

    trainfinger=1 testingfinger=(1:8); testingfinger = testingfinger(~ismember(testingfinger,trainfinger ...

  8. Matlab神经网络验证码识别

    本文,将会简述如何利用Matlab的强大功能,调用神经网络处理验证码的识别问题.  预备知识,Matlab基础编程,神经网络基础.  可以先看下: Matlab基础视频教程 Matlab经典教程--从 ...

  9. Django问题2

    接触django是从上个月开始,学习python时间也不长,但我经常在社区看看别人发表的文章,早上看到一篇不错的博客,却一直不能访 问,最终从bing的缓存里找到,因为害怕丢失和忘掉,所以顺便翻译过来 ...

  10. [转]C#操作Excel初探

    近期一段时间正好在做winform导出Excel报表的问题,学习了一下C#操作Excel的一些方法(如:向Excel中插入图片:删除Excel指定sheet中的某行或某列,在Excel指定的单元格中画 ...