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

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)对于AtomicIntegerFieldUpdaterAtomicLongFieldUpdater只能修改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. window.location 对象中各种方法的用途

    一.简介 属性 描述 hash 从井号 (#) 开始的 URL(锚) host 主机名和当前 URL 的端口号 hostname 当前 URL 的主机名 href 完整的 URL pathname 当 ...

  2. (转)JS的splice()方法在for循环中的使用问题

    在写JS代码时,我们常常使用 splice 函数来删除数组中的元素,因为 splice 函数会直接对数组进行修改,从而不需再自己写一个算法来移动数组中的其他元素填补到被删除的位置.splice 功能十 ...

  3. VS2010-MFC(Ribbon界面开发:创建Ribbon样式的应用程序框架)

    转自:http://www.jizhuomi.com/software/251.html 上一节讲了GDI对象之画刷CBrush,至此图形图像的入门知识就讲完了.从本节开始将为大家带来Ribbon界面 ...

  4. Cocos2d-x通过Jni实现C++与Java相互调用

    在cocos2dx项目中与运营平台(java sdk)对接时使用了JNI. 通过C++调用Java 在JniUtil.h文件中如下实现: #ifndef _JNIUTIL_H_ #define _JN ...

  5. java读取字符串,生成txt文件

    /** * 读取字符串,生成txt 文件 已解决未设置编码时,在项目中直接打开文件,中文乱码问题 * WriteText.writeToText(musicInfo,fileName)直接调用 * * ...

  6. maven 运行run as maven build的时候报错

    eclipse中使用maven插件的时候,运行run as maven build的时候报错 -Dmaven.multiModuleProjectDirectory system propery is ...

  7. 2019-8-31-C#-如何给-ValueTuple-返回值添加注释

    title author date CreateTime categories C# 如何给 ValueTuple 返回值添加注释 lindexi 2019-08-31 16:55:58 +0800 ...

  8. 关于Android 的网址

    Android 官方API查询网址 https://developer.android.google.cn/ 第三方镜像Android API查询网址 (比官方浏览速度快一些,缺点现有API较低) h ...

  9. Nginx的安装--------tar包安装

    Nginx的安装,在网上搜索是很多的结果,但是 真的安装起来却花费了不少 心思,总结起来就是依赖包安装了,但是没有指定对的路径,在安装的过程中遇到过两个问题: ①make[1]: *** [/usr/ ...

  10. 2016.9.3初中部上午NOIP普及组比赛总结

    2016.9.3初中部上午NOIP普及组比赛总结 链接:https://jzoj.net/junior/#contest/home/1339 这次真爽,拿了个第四!(我还被班主任叫过去1小时呢!) 进 ...