深入浅出 Java Concurrency (3): 原子操作 part 2[转]
在这一部分开始讨论数组原子操作和一些其他的原子操作。
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[转]的更多相关文章
- 深入浅出 Java Concurrency (4): 原子操作 part 3 指令重排序与happens-before法则
转: http://www.blogjava.net/xylz/archive/2010/07/03/325168.html 在这个小结里面重点讨论原子操作的原理和设计思想. 由于在下一个章节中会谈到 ...
- 《深入浅出 Java Concurrency》——原子操作
part1 从AtomicInteger開始 从相对简单的Atomic入手(java.util.concurrent是基于Queue的并发包.而Queue.非常多情况下使用到了Atomic操作.因此首 ...
- 深入浅出 Java Concurrency (4): 原子操作 part 3 指令重排序与happens-before法则[转]
在这个小结里面重点讨论原子操作的原理和设计思想. 由于在下一个章节中会谈到锁机制,因此此小节中会适当引入锁的概念. 在Java Concurrency in Practice中是这样定义线程安全的: ...
- 深入浅出 Java Concurrency (3): 原子操作 part 2
转:http://www.blogjava.net/xylz/archive/2010/07/02/325079.html 在这一部分开始讨论数组原子操作和一些其他的原子操作. AtomicInteg ...
- 深入浅出 Java Concurrency (2): 原子操作 part 1
转:http://www.blogjava.net/xylz/archive/2010/07/01/324988.html 从相对简单的Atomic入手(java.util.concurrent是基于 ...
- 深入浅出 Java Concurrency (2): 原子操作 part 1[转]
从相对简单的Atomic入手(java.util.concurrent是基于Queue的并发包,而Queue,很多情况下使用到了Atomic操作,因此首先从这里开始).很多情况下我们只是需要一个简单的 ...
- 深入浅出 Java Concurrency (5): 原子操作 part 4 CAS操作
在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁(后面的章节还会谈到锁). 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度 ...
- 深入浅出 Java Concurrency (5): 原子操作 part 4[转]
在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁(后面的章节还会谈到锁). 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度 ...
- 深入浅出 Java Concurrency (15): 锁机制 part 10 锁的一些其它问题
主要谈谈锁的性能以及其它一些理论知识,内容主要的出处是<Java Concurrency in Practice>,结合自己的理解和实际应用对锁机制进行一个小小的总结. 首先需要强调的 ...
随机推荐
- Socket.EndReceive 方法 (IAsyncResult)
.NET Framework (current version) 其他版本 .NET Framework 4 .NET Framework 3.5 .NET Framework 3.0 . ...
- C++命令行多文件编译(g++)
在刚开始学Java时用命令行进行编译代码.而C++一直在用IDE, 这次尝试下命令行编译.vs下也可以用cl.exe.link.exe等命令来进行编译 但这次是通过安装MinGW来学习命令编译,主要用 ...
- Java开发系列-注解
概述 在JDK5之后提供了一个新特性,和类.接口同级.定义时使用的关键字是@interface.注解主要有三个作用,分别是编译检查.替代配置文件.定义注解(元注解).分析代码(用到反射).注解的本质就 ...
- login-Linux必学的60个命令
1.作用 login的作用是登录系统,它的使用权限是所有用户. 2.格式 login [name][-p ][-h 主机名称] 3.主要参数 -p:通知login保持现在的环境参数. -h:用来向远程 ...
- 【主席树】 [CQOI2015]任务查询系统
模板题... 差分,然后用主席树维护时间点上的优先值和就好了 就是细节烦... #include<bits/stdc++.h> #define int long long #define ...
- Jmeter 录制脚本【转】
Jmeter 录制脚本[转] Jmeter中有2种方法可以录制脚本. 不过我个人非常不推荐录制脚本,录制的脚本混乱,需要再次加工才能使用. 像我这么精通HTTP协议的人. 一直都是使用Fiddler ...
- windows安装apache系统中无apache2服务解决方案
一直都是用WIN开发PHP,今天有用户反映SHUGUANG CMS在APACHE+PHP中不能正常运行,只好自己机器配置个环境测试(http://xz.8682222.com)遇到点小问题,搜索相关资 ...
- MaxCompute安全管理指南-案例篇
通过<MaxCompute安全管理-基础篇>了解到MaxCompute和DataWorks的相关安全模型.两个产品安全方面的关联,以及各种安全操作后,本篇主要给出一些安全管理案例,给安全管 ...
- thinkphp 命名范围
在应用开发过程中,使用最多的操作还是数据查询操作,凭借ThinkPHP的连贯操作的特性,可以使得查询操作变得更优雅和清晰,命名范围功能则是给模型操作定义了一系列的封装,让你更方便的操作数据. 命名范围 ...
- RabbitMQ代码操作之发消息和序列化机制
几个自动配置类: 1.RabbitAutoConfiguration2.有自动配置了连接工厂 ConnectionFactory3.RabbitProperties 封装了RabbitMQ的配置4.R ...