今天我们介绍原子类的最后一个类型—-对象的属性修改类型: 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. BZOJ 2152:聪聪可可(树上点分治)

    题目链接 题意 中文题意. 思路 和上一题类似,只不过cal()函数需要发生变化. 题目中要求是3的倍数,那么可以想到 (a + b) % 3 == 0 和 (a % 3 + b % 3) % 3 = ...

  2. jsp传值

    是由a1.jsp发出请求然后由a2.jsp转发给ok.jsp,由ok.jsp响应a1.jsp. 但是这个转发过程是在服务端发生的,客户端不知道所以地址是不变的 转发请求的代码: request.get ...

  3. 站在巨人的肩膀上看Servlet——原来如此(更适合初学者认识Servlet)

    前言: 有段时间没更新博客了,这段时间因为要准备考试,考完试后又忙了一阵别的事,一直没能静下心来写博客.大学考试真是越来越恶心了,各种心酸,那酸爽,够味.不过还好,马上就要大三了,听大三学长学姐说大三 ...

  4. 【拓扑排序】排队-C++

    描述 今天,学校老师让同学们排成一队,准备带大家出去玩,一共有 n 名同学,排队的时候同学们向老师提了 m 条要求,每一条要求是说同学 x 一定要排在同学 y 之前,老师现在想找到一种排队方式可以满足 ...

  5. java面试题库(长期)

    本文内容来自互联网各种面试实例,以及自己的面试经历,主要是中级开发的面试题 初中级java面试主要分为几个部分: 0.序 1.java基础 2. java多线程 3. jvm知识 4. spring等 ...

  6. 【Android UI】自定义带按钮的标题栏

    自定义标题栏在很多的android app中很常见,可以说是一种很有用的UI设计方法.自 己也本着学习的态度,经过一番各种坑,终于实现了,现总结如下: 一:大致流程 1.      对指定的andro ...

  7. MySql的数据库优化到底优啥了都??(1)

    嘟嘟最不愿意做的就是翻招聘信息. 因为一翻招聘信息,工作经历你写低于两年都不好意思,前后端必须炉火纯青融汇贯通,各式框架必须如数家珍不写精通咋的你也得熟练熟练, 对了你是985吗?你是211吗??你不 ...

  8. [小米OJ] 11. 构建短字符串

    思路 排序后对两个字符串遍历 function solution(line) { var str = line.split(" "); var str1 = str[0].spli ...

  9. 基于tcp协议的登录,文件上传和下载

    ​ [1]先登录,登录不成功循环登录,直到成功.登录成功后可以选择上传或者下载,上传有对应的文件,可选择上传哪个:下载有对应的文件,可选择下载哪个 ​ [2]登录,上传,下载时最好设置状态码,客户端和 ...

  10. 你真的了解 Cookie 和 Session 吗

    我在做面试官的时候,曾经问过很多朋友这个问题: Cookie 和 Session 有什么区别呢?大部分的面试者应该都可以说上一两句,比如:什么是 Cookie?什么是 Session?两者的区别等. ...