今天我们介绍原子类的最后一个类型—-对象的属性修改类型: AtomicIntegerFieldUpdater,AtomicLongFieldUpdater,AtomicReferenceFieldUpdater。有了这几个方法,普通的变量也能享受原子操作了。

1. 开胃菜

由API我们知道AtomicIntegerFieldUpdater,AtomicLongFieldUpdater,AtomicReferenceFieldUpdater通过反射原子更新对象的字段,既然他们的作用是更新字段我们知道有些类型的字段是不可被更新的,所以被更新的字段是有一定的要求:

1. 必须是volatile类型(volatile是线程可见变量,保存在Jvm的主内存中,而不是线程的工作内存里面),

2. 字段的描述类型(修饰符public/protected/default/private)是调用者与操作对象字段的关系一致,

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

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

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

2. 使用它

上面我们说了这几个类的作用是让普通类型的字段也能享受到原子操作,假如原本有一个变量是int型,并且很多地方都应用了这个变量,但是在某个场景下,想让int型变成AtomicInteger,但是如果直接改类型,就要改其他地方的应用。AtomicIntegerFieldUpdater就是为了解决这样的问题产生的。

AtomicIntegerFieldUpdater,AtomicLongFieldUpdater分别是对int和long类型的字段操作,AtomicReferenceFieldUpdater是对引用型的对象操作,并且在API中他们的操作方法与普通的AtomicInteger差不多,所以方法我就不再罗列,我们就直接使用吧。

我们来看AtomicIntegerFieldUpdater的例子:

/**
* allscore 如果和 score 的结果相同则说明线程是安全的
*/
public class AtomicIntegerFieldUpdaterTest {
public final static AtomicIntegerFieldUpdater<AA> vv = AtomicIntegerFieldUpdater.newUpdater(AA.class, "score"); //newUpdater方法为AA类中的score 对象创造一个更新器 public static AtomicInteger allscore = new AtomicInteger(0); public static void main(String[] args) throws InterruptedException
{
final AA stu = new AA();
Thread[] t = new Thread[10000];
for (int i = 0; i < 10000; i++)
{
t[i] = new Thread() {
@Override
public void run()
{
if(Math.random()>0.4)
{
vv.incrementAndGet(stu);
allscore.incrementAndGet();
}
}
};
t[i].start();
}
for (int i = 0; i < 10000; i++)
{
t[i].join();
}
System.out.println("score="+stu.getScore());
System.out.println("allscore="+allscore);
}
} class AA{
int id;
volatile int score;
public int getScore()
{
return score;
}
public void setScore(int score)
{
this.score = score;
}
}

输出结果:

score=6032
allscore=6032

AtomicIntegerFieldUpdater包装过的int类型的score与 AtomicInteger 的allscore输出的值是一样的,足以见他们所起到的作用是一样。

我们说了AtomicIntegerFieldUpdater,那么AtomicLongFieldUpdater与它的用法大同小异,就不再说明。我们说这几个类是基于反射的实用工具,那么到底是怎么个反射法呢,我们不妨看看源码体验一下,上面用到了AtomicIntegerFieldUpdater.newUpdater()方法来指定类中的字段,我们不妨看看这个newUpdater是怎么执行的:

newUpdater()方法:

@CallerSensitive
public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName, Reflection.getCallerClass());
}

我们看到在newUpdater方法上有一个注解:@CallerSensitive,关于这个注解我们可以探究一天的,暂时先埋一个伏笔哈,我们直接跟进去AtomicIntegerFieldUpdaterImpl方法:

AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName, Class<?> caller) {
Field field = null;
int modifiers = 0;
try {
field = tclass.getDeclaredField(fieldName);
modifiers = field.getModifiers();
sun.reflect.misc.ReflectUtil.ensureMemberAccess(
caller, tclass, null, modifiers);
sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
} catch (Exception ex) {
throw new RuntimeException(ex);
} Class fieldt = field.getType();
if (fieldt != int.class)
throw new IllegalArgumentException("Must be integer type"); if (!Modifier.isVolatile(modifiers))
throw new IllegalArgumentException("Must be volatile type"); this.cclass = (Modifier.isProtected(modifiers) &&
caller != tclass) ? caller : null;
this.tclass = tclass;
offset = unsafe.objectFieldOffset(field);
}

我们能看到该类里面都是我们常见到的反射的机制,除了sun.reflect.misc.ReflectUtil这个包里面的我们没用到以外。

我们再看一下AtomicReferenceFieldUpdater的使用:

public class AtomicReferenceFieldUpdaterTest {
public static void main(String[] args) {
TestAA testAA = new TestAA("xiaoming","nv",12);
AtomicReferenceFieldUpdater Updater = AtomicReferenceFieldUpdater.newUpdater(TestAA.class,String.class,"name");
Updater.compareAndSet(testAA,testAA.name,"liming");
System.out.println(testAA.getName());
}
}
class TestAA{
volatile String name;
volatile String sex;
volatile int age; public TestAA(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
}

输出为:

liming

Process finished with exit code 0

java并发编程(十四)----(JUC原子类)对象的属性修改类型介绍的更多相关文章

  1. java并发编程(十)----JUC原子类介绍

    今天我们来看一下JUC包中的原子类,所谓原子操作是指不会被线程调度机制打断的操作:这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程),原子操作可以是 ...

  2. [Java并发编程(四)] Java volatile 的理论实践

    [Java并发编程(四)] Java volatile 的理论实践 摘要 Java 语言中的 volatile 变量可以被看作是一种 "程度较轻的 synchronized":与 ...

  3. java多线程系类:JUC原子类:01之框架

    本系列内容全部来自于http://www.cnblogs.com/skywang12345/p/3514589.html 特在此说明!!!!! 根据修改的数据类型,可以将JUC包中的原子操作类可以分为 ...

  4. java并发编程工具类JUC第四篇:LinkedBlockingQueue链表队列

    在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue. LinkedBlockingQueue 队列是Blo ...

  5. java多线程系类:JUC原子类:03之AtomicLongArray原子类

    概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数 ...

  6. java并发编程工具类JUC第七篇:BlockingDeque双端阻塞队列

    在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...

  7. java并发编程工具类JUC第八篇:ConcurrentHashMap

    在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...

  8. 《Java并发编程实战》第三章 对象的共享 读书笔记

    一.可见性 什么是可见性? Java线程安全须要防止某个线程正在使用对象状态而还有一个线程在同一时候改动该状态,并且须要确保当一个线程改动了对象的状态后,其它线程能够看到发生的状态变化. 后者就是可见 ...

  9. java并发编程(四) 线程池 & 任务执行、终止源码分析

    参考文档 线程池任务执行全过程:https://blog.csdn.net/wojiaolinaaa/article/details/51345789 线程池中断:https://www.cnblog ...

随机推荐

  1. .NET中生成动态验证码

    .NET中生成动态验证码 验证码是图片上写上几个字,然后对这几个字做特殊处理,如扭曲.旋转.修改文字位置,然后加入一些线条,或加入一些特殊效果,使这些在人类能正常识别的同时,机器却很难识别出来,以达到 ...

  2. C语言学习书籍推荐《学通C语言的24堂课》下载

    下载地址:点我 编辑推荐 <学通C语言的24堂课>:用持续激励培养良好习惯以良好习惯铸就伟大梦想——致亲爱的读者朋友在开始学习<学通C语言的24堂课>的同时,强烈建议读者朋友同 ...

  3. NetCore 获取appsetting.json 文件中的配置

    1. using Microsoft.Extensions.Configuration public class HomeController : Controller { public IConfi ...

  4. CTSC&APIO被教做人记

    DAY 0: 早早起来从衡水出发,在去火车站的路上明白了HZOI总是差点误车的真相……上了绿皮火车之后由于没网没流量就开始看政治书应付学考,然而并不是很能看进去,感觉初中学的比高中学的不知道高到哪里去 ...

  5. python基础知识五 各类型数据方法补充,转换,分类,编码+坑中菜

    3.9各类型数据方法补充,转换,分类,编码,坑中菜 3.9.1数据类型方法补充 1.str:不可变 补充方法 s1.capitalize():首字母大写 s1 = "alex" s ...

  6. Eclipse中Cannot nest src folder解决方法

    错误示例: : Java Model Status [Cannot nest output folder 'xxx/bin/main' inside output folder 'xxx/bin'] ...

  7. 关于iphone手机上点击事件不起作用

    今天调试手机端H5页面的时候,发现一个很坑的问题,绑定的点击事件不起效果,安卓上都没问题,事件能正确触发,但是在iPhone没反应. 开始觉得是写法问题,后来发现,是由于iPhone上,点击的对象,必 ...

  8. 题解 P3811 【【模板】乘法逆元】

    P3811 [模板]乘法逆元 一个刚学数论的萌新,总结了一下这题的大部分做法 //一.费马小定理+快速幂 O(nlogn) 64分 #include<cstdio> using names ...

  9. Android拨打电话权限总结

    android在6.0和6.0以上拨打电话的权限声明 /** * 打电话 * * @param phoneNumber */ protected void startCallPhone(String ...

  10. 高级MySQL

    一.MySQL的架构介绍 1.高级MySQL MySQL内核 SQL优化 MySQL服务器的优化 各种参数常亮设定 查询语句优化 主从复制 软硬件升级 容灾备份 SQL编程 2.MySQL的Linux ...