java并发编程(十四)----(JUC原子类)对象的属性修改类型介绍
2017-01-17 22:13
295 查看
今天我们介绍原子类的最后一个类型—-对象的属性修改类型: 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。
AtomicIntegerFieldUpdater,AtomicLongFieldUpdater分别是对int和long类型的字段操作,AtomicReferenceFieldUpdater是对引用型的对象操作,并且在API中他们的操作方法与普通的AtomicInteger差不多,所以方法我就不再罗列,我们就直接使用吧。
我们来看AtomicIntegerFieldUpdater的例子:
输出结果:
AtomicIntegerFieldUpdater包装过的int类型的score与 AtomicInteger 的allscore输出的值是一样的,足以见他们所起到的作用是一样。
我们说了AtomicIntegerFieldUpdater,那么AtomicLongFieldUpdater与它的用法大同小异,就不再说明。我们说这几个类是基于反射的实用工具,那么到底是怎么个反射法呢,我们不妨看看源码体验一下,上面用到了AtomicIntegerFieldUpdater.newUpdater()方法来指定类中的字段,我们不妨看看这个newUpdater是怎么执行的:
newUpdater()方法:
我们看到在newUpdater方法上有一个注解:@CallerSensitive,关于这个注解我们可以探究一天的,暂时先埋一个伏笔哈,我们直接跟进去AtomicIntegerFieldUpdaterImpl方法:
我们能看到该类里面都是我们常见到的反射的机制,除了sun.reflect.misc.ReflectUtil这个包里面的我们没用到以外。
我们再看一下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原子类)数组类型介绍
- java并发编程(十一)----(JUC原子类)基本类型介绍
- java并发编程(十三)----(JUC原子类)引用类型介绍(CAS和ABA的介绍)
- java并发编程(十)----JUC原子类介绍
- Matlab Tricks(十四) —— 句柄(handle)(图形对象属性的读取与修改)
- Delphi修改对象中非读方法的只读属性
- 窗体继承时对象属性的修改问题
- 对对象类型和调用方法属性进行存储以提升反射性能
- 【转载】EXCEL中条码问题:条形码能插入,但只有一种类型,数字不能改,修改属性后也不显示
- javascript调试测试,利用vs2008:智能对象类型感知,方法及属性提示;立即窗口调试等
- 利用反射机制动态获取对象属性名称及数据类型
- javascript中关于window对象属性的全面介绍
- 对对象类型和调用方法属性进行存储以提升反射性能
- Flex 对象属性 对象类型
- 使用表达式树访问对象、类型及成员(下):获取对象和属性的值
- JavaScript 对象的属性和方法4种不同的类型
- [对象和类型]4.C#的属性
- static 类型属性(局部静态对象)
- 对javascript基本对象的属性以及方法的实例介绍
- 对对象类型和调用方法属性进行存储以提升反射性能