引言
接下来是原子类序章中我们提到的原子更新字段类,它们是AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater。其实就是了原子的更新一个引用类型的整形字段、long型字段、引用类型字段。
AtomicIntegerFieldUpdater
首先根据如下的类结构可见,它本身是一个抽象方法,提供了一个静态工厂方法newUpdater()来生成实例。
public abstract class AtomicIntegerFieldUpdater<T> { @CallerSensitive public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { return new AtomicIntegerFieldUpdaterImpl<U> (tclass, fieldName, Reflection.getCallerClass()); } /** * Protected do-nothing constructor for use by subclasses. */ protected AtomicIntegerFieldUpdater() { } .....
接着来看它的实现类,它的实现类AtomicIntegerFieldUpdaterImpl是它的一个私有静态内部类:
private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T> { private static final Unsafe unsafe = Unsafe.getUnsafe(); private final long offset; private final Class<T> tclass; private final Class<?> cclass; AtomicIntegerFieldUpdaterImpl(final Class<T> tclass, final String fieldName, final Class<?> caller) { final Field field; final int modifiers; try { field = AccessController.doPrivileged( new PrivilegedExceptionAction<Field>() { public Field run() throws NoSuchFieldException { return tclass.getDeclaredField(fieldName); } }); modifiers = field.getModifiers(); sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers); ClassLoader cl = tclass.getClassLoader(); ClassLoader ccl = caller.getClassLoader(); if ((ccl != null) && (ccl != cl) && ((cl == null) || !isAncestor(cl, ccl))) { sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); } } catch (PrivilegedActionException pae) { throw new RuntimeException(pae.getException()); } 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); } .....
从它的实例构造方法可见,它首先会对目标class及其指定的字段进行检测,主要是访问权限、数据类型是否是int,是否 是volatile修饰,最后当然还有通过unsafe获取目标字段的偏移量,为后面的CAS原子操作作准备。
从以上方法我们可以得出,要想使用AtomicIntegerFieldUpdater原子的更新一个对象的某个字段,必须满足以下条件:
- 调用者必须有对目标类的访问权限;
- 目标字段必须是整形int或者Integer;
- 目标字段必须是public修饰的;
- 目标字段必须是volatile修饰的。
另外,实现类AtomicIntegerFieldUpdaterImpl还实现了一些AtomicIntegerFieldUpdater的基础的原子更新的抽象方法:
public boolean compareAndSet(T obj, int expect, int update) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.compareAndSwapInt(obj, offset, expect, update); } public boolean weakCompareAndSet(T obj, int expect, int update) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.compareAndSwapInt(obj, offset, expect, update); } public void set(T obj, int newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); unsafe.putIntVolatile(obj, offset, newValue); } public void lazySet(T obj, int newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); unsafe.putOrderedInt(obj, offset, newValue); } public final int get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.getIntVolatile(obj, offset); } public int getAndSet(T obj, int newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.getAndSetInt(obj, offset, newValue); } public int getAndIncrement(T obj) { return getAndAdd(obj, 1); } public int getAndDecrement(T obj) { return getAndAdd(obj, -1); } public int getAndAdd(T obj, int delta) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.getAndAddInt(obj, offset, delta); } public int incrementAndGet(T obj) { return getAndAdd(obj, 1) + 1; } public int decrementAndGet(T obj) { return getAndAdd(obj, -1) - 1; } public int addAndGet(T obj, int delta) { return getAndAdd(obj, delta) + delta; }
这些方法和AtomicInteger提供的方法一致,不再熬述。剩下的其他的一些方法和AtomicInteger提供的原子更新方法几乎一样,都分为那四大原子更新方法,也不在一一列举。
AtomicLongFieldUpdater
再看AtomicLongFieldUpdater,它和AtomicIntegerFieldUpdater的结构基本一致,也是一个抽象方法,不同的是它是对long型字段的原子更新,而不是整形。
另外还有一个比较重要的区别就是,它的实现类有两个,根据平台是否支持8字节的CAS操作来选择不同的实现:
@CallerSensitive public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { Class<?> caller = Reflection.getCallerClass(); if (AtomicLong.VM_SUPPORTS_LONG_CAS) return new CASUpdater<U>(tclass, fieldName, caller); else return new LockedUpdater<U>(tclass, fieldName, caller); }
如果平台支持8字节的CAS操作,那么实现逻辑 CASUpdater就和AtomicIntegerFieldUpdater中的实现类似,也就是直接使用CAS操作达到原子操作的目的,如果平台不支持8字节的CAS操作,那么就使用内部加锁的方式实现对8字节的原子更新操作,如下所示为当平台不支持8字节的CAS操作时的内部加锁实现方式:
public boolean compareAndSet(T obj, long expect, long update) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); synchronized (this) { long v = unsafe.getLong(obj, offset); if (v != expect) return false; unsafe.putLong(obj, offset, update); return true; } } public boolean weakCompareAndSet(T obj, long expect, long update) { return compareAndSet(obj, expect, update); } public void set(T obj, long newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); synchronized (this) { unsafe.putLong(obj, offset, newValue); } } public void lazySet(T obj, long newValue) { set(obj, newValue); } public long get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); synchronized (this) { return unsafe.getLong(obj, offset); } }
可见当不支持8字节的CAS操作时,JDK8采用的是synchronized锁实现。
AtomicLongFieldUpdater和AtomicIntegerFieldUpdater一样,可以对所操作的字段进行加减和更复杂的函数式运算,具体方法和AtomicLong类似,不再一一列举了。
AtomicReferenceFieldUpdater
最后再看AtomicReferenceFieldUpdater,它同样是一个抽象类,也是通过一个工厂方法生成原子更新器实例,同样它的实现方法也是通过CAS实现,所要操作的字段也必须是特定类型的public volatile修饰的。
AtomicReferenceFieldUpdater比 AtomicReference的原子更新操作更细粒度和更精确,它比AtomicReference这种直接更新整个对象要高效的多。
测试代码:
public class AtomicIntegerFieldUpdaterTest { private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater .newUpdater(User.class, "old"); public static void main(String[] args) { User user = new User("conan", 10); System.out.println(a.getAndIncrement(user)); //10 System.out.println(a.get(user)); //11 } public static class User { private String name; public volatile int old; public User(String name, int old) { this.name = name; this.old = old; } public String getName() { return name; } public int getOld() { return old; } } }
相关推荐
- `AtomicReference`:存储对象引用的原子操作,可以实现无锁的数据结构。 2. 数组版本的原子类: - `AtomicIntegerArray`、`AtomicLongArray`和`AtomicReferenceArray`:分别对应整型、长整型和引用类型的数组,...
而对于包含很多成员的数据结构而言,需要提供一种机制达到同步的效果,锁提供的就是这样一种机制:它就如同一把门锁,门后的房间可想像成一个临界区。在一个指定时间内,房间里只能有一个执行线程存在,当一个线程...
4. **事务处理**:在并发环境中,事务的ACID属性(原子性、一致性、隔离性和持久性)需要通过合适的数据结构和算法来保障。 5. **空间数据结构**:对于地理信息系统(GIS)等应用,空间数据结构如R树、四叉树等用于...
其数据结构丰富,支持字符串、哈希、列表、集合和有序集合等多种类型,使得Redis在处理各种复杂数据操作时表现出色。 1. **Redis的启动过程** Redis的启动主要包括以下步骤: - 首先,检查配置文件(默认为`redis...
- **NTP报文格式**:理解NTP数据包的结构,包括时间戳字段、模式字段、版本字段等,以便正确构建和解析报文。 - **网络通信**:使用套接字编程来发送和接收UDP数据包,因为NTP通常运行在UDP协议上。 - **时间转换**...
5. 使用线程安全的数据结构:C#库中提供了如`ConcurrentDictionary`、`ConcurrentQueue`等线程安全的数据结构,它们内部已经实现了线程同步,可以直接使用。 总结起来,C#中的结构体字段赋值在多线程环境下可能存在...
它通过检查和更新一个顺序字段来实现同步,简化了对简单数据结构的保护。 6. **完成变量(completion variable)**:完成变量用于等待某个事件的发生,例如等待一个任务完成。一个线程会等待完成变量被标记为完成,...
它不仅提供了传统的键值对存储服务,还支持多种复杂的数据结构如哈希、列表、集合以及有序集合等。这种多样的数据类型支持使得Redis不仅仅是一个简单的键值存储系统,而是被广泛认为是一种“数据结构服务器”。 ###...
在`Redis`中,可以选择`String`(用于简单的键值对)或`Hash`数据结构(对于多个相关字段)来存储`session`。 为了实现`session`的自动同步,我们需要处理以下几点: - **过期策略**:确保`Redis`中的`session`有...
通过特定的数据结构(原子),Quick Time 文件能够高效地组织这些媒体流,并确保它们在播放时能够同步。 #### 原子(Atoms) 原子是 Quick Time 文件中的基本构建单元。每个原子都有一个固定的头部,其中包含了...
首先,数据库结构是指数据库中数据的组织方式,包括表、字段、索引、视图、存储过程等元素。在设计数据库时,需要遵循关系型数据库理论,如范式理论,以确保数据的一致性和完整性。例如,第一范式(1NF)要求每个...
3. 结果集解析器:将查询结果转换为易于访问的数据结构,允许通过字段名进行访问。 在实际应用中,这个接口类可能会被设计成一个面向对象的类,提供如`connect_to_database()`、`execute_sql()`、`get_result_by_...
这一步骤通常涉及到规范化设计,确保数据结构的合理性。 #### 数据同步与交互 在实现了XML与数据库之间的转换后,还需要关注数据的安全性、一致性和并发控制等问题。例如,在进行数据同步时,可以采用以下策略: ...
总结来说,实现Redis与MySQL的数据一致性涉及多个层面,包括数据同步策略、数据结构映射、分布式特性处理、中间件工具以及容错机制。在实际应用中,需要根据业务场景选择合适的方法,并不断优化以提高系统的稳定性和...
总的来说,Java的Unsafe类虽然强大且高效,但其内部操作直接触及JVM的底层,使用不当可能会引发安全问题,因此在实际开发中应谨慎使用,通常只在对性能有极致追求或者需要自定义高级并发数据结构时考虑。理解并恰当...
这两个步骤并不是原子操作,在多线程环境下,如果不进行适当的同步控制,可能会出现一个元素被多个线程重复添加的情况,导致数组大小和实际存储的元素数量不一致。 为了解决这一线程不安全的问题,在多线程环境下...
当字段数量或字段长度超出限制时,会切换到hashtable数据结构。 Redis的设计遵循数据库规范化原则,虽然它不是关系型数据库,但其数据结构设计仍然考虑了数据的一致性和完整性。这里提到了数据库范式,包括第五范式...
- **解题思路**:理解题目需求,选择合适的数据结构和算法。 ### C++ #### new/delete与malloc/free的区别 - **`new`/`delete`**:不仅分配/释放内存,还会调用构造/析构函数。 - **`malloc`/`free`**:仅分配/...
索引是一种数据结构,用于加快查询性能。索引可以快速地定位指定的数据,减少查询时间。 * 索引的优点:加快查询速度、减少磁盘 I/O、降低 CPU 负载。 * 索引的缺点:占用存储空间、降低写入性能。 高并发高...
- **概念**:`java.util.concurrent`包中的并发集合类如`ConcurrentHashMap`、`CopyOnWriteArrayList`等,提供了线程安全的数据结构。 - **优势**:相比传统的同步集合类,这些并发集合提供了更好的并发性能。 ####...