AtomicLong.lazySet是如何工作的?

Jackson Davis说:
为一个AtomicLong对象设置一个值,jvm会确保其他线程读取到最新值,原子类和voliatile变量也是一样的,这是由依赖于硬件的系统指令(如x86的xchg)实现的。lazySet却是无法保证这一点的方法,所以其他线程在之后的一小段时间里还是可以读到旧的值。

这有什么好处呢?

性能:在多核处理器下,内存以及cpu缓存的读和写常常是顺序执行的,所以在多个cpu缓存之间同步一个内存值的代价是很昂贵的。

如何实现呢?

大多数的原子类,比如AtomicLong本质上都是一个Unsafe和一个volatile Long变量的包装类。值得注意的是AtomicLong.lazySet方法实际是调用了本地方法Unsafe.putOrderedLong,本地方法Unsafe.putOrderedLong的实现可以参考http://hg.openjdk.java.net/jdk7/…。从Unsafe的代码中可以发现Unsafe_setOrderedLong是一个本地方法(c++实现),它仅调用了SET_FIELD_VOLATILE,这很是奇怪,我们期望共享的Unsafe_setLongVolatile拥有不同的语义。PS:在非增强版本中,setOrdered仅仅是调用了setVolatile方法,很是让人失望。深入查看你会发现其实他们是相同的,SET_FIELD_VOLATILE是一个OrderAccess:release_store_fence的包装。可以在Linux x86的代码http://hg.openjdk.java.net/jdk7/…中找到此方法的实现,在64bit x86系统中采用xchgq来代码,64位版本指令的问题我上面有提到过。

ps:从理论上讲lazySet能比一个标准的volatile变量的写性能更好。但是我在openJdk里没有找到相关代码。

Felix Sulima说:
sun.misc.unsafe很多方法被jvm增强了,JIT(just in time运行时编译执行的技术)直接解释而忽略原始的实现。可以在这里找到这个例子:src/share/vm/classfile/vmSymbols.hpp@3facbb14e873列表中的native方法仅仅是非JIT环境下的一个备份的内部方法。例如,如果它没有被调用(我也不知道是什么原因),因此这些方法缺乏一些必要的优化。从Talk from JAX London的幻灯片11-12可以看到AtomicLong.lazySet(…)在x86系统上会被编译成“mov”指令。这里是Google Group里关于如何获得JIT装配的一个描述。

### 线程安全的定义 线程安全是指在多线程环境下运行某个程序片段时,无论有多少线程同时执行该代码段,其行为都能保持一致并符合预期[^2]。换句话说,即使多个线程访问共享资源,它们之间的操作也不会相互干扰,从而保证数据的一致性和完整性。 如果一段代码在线程间存在互相影响的情况,则被认为是线程不安全的。这种情况下,结果可能会因线程调度的不同而发生变化,甚至引发不可预测的行为或错误[^2]。 --- ### 解决线程安全问题的方法及最佳实践 以下是几种常见的解决线程安全问题的方式及其适用场景: #### 1. 使用 `synchronized` 关键字 `synchronized` 是 Java 中用于实现同步的关键字,可以用来修饰方法或者代码块。它通过加锁机制确保同一时间只有一个线程能够进入被标记为 synchronized 的区域,从而避免了多线程间的冲突[^1]。 示例代码如下: ```java public class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } } ``` --- #### 2. 利用 `volatile` 关键字 当变量可能被多个线程修改且不需要复杂的原子性保障时,可以使用 `volatile` 关键字声明该变量。这能确保每次读取到的是最新的值,而不是缓存中的旧值。 注意:`volatile` 并不能替代锁定机制,仅适用于简单的状态标志或其他无需复合操作的情形。 --- #### 3. 原子类的应用 Java 提供了一系列位于 `java.util.concurrent.atomic` 包下的原子类(如 `AtomicInteger`, `AtomicLong`),这些类提供了高效的无锁算法来完成一些基本的操作,比如自增、比较交换等[^1]。 实例演示: ```java import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } } ``` --- #### 4. 锁机制 (Lock 接口) 相比传统的 `synchronized` 方法/块,显式的 Lock 对象提供了更加灵活的功能,例如尝试获取锁、定时等待锁释放等功能。 下面是一个基于 ReentrantLock 的例子: ```java import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockedResource { private final Lock lock = new ReentrantLock(); private int value; public void setValue(int newValue) { lock.lock(); // 获取锁 try { this.value = newValue; } finally { lock.unlock(); // 确保最终解锁 } } public int getValue() { lock.lock(); try { return value; } finally { lock.unlock(); } } } ``` --- #### 5. 并发集合 标准的 Collection 类型并非线程安全设计,因此在高并发场景下应考虑采用专门优化过的并发集合类型,像 `ConcurrentHashMap`, `CopyOnWriteArrayList` 等。 举例说明如何利用 ConcurrentHashMap 完成高效的数据存储与检索任务: ```java import java.util.concurrent.ConcurrentHashMap; public class ConcurrentMapExample { private static final ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(); public static void put(String key, String value) { map.put(key, value); } public static String get(String key) { return map.get(key); } } ``` --- #### 6. 避免共享可变状态 一种更为激进但也非常有效的策略是完全消除对象内部的状态共享,转而依赖于函数式编程风格或是不可变对象的设计理念[^3]。这样从根本上杜绝了由于竞态条件引起的潜在风险。 例如,在 Python 编程语言里,我们可以借助只读视图代替原始列表传递给不同工作单元处理: ```python from copy import deepcopy class SafeProcessor: def __init__(self, data): self._data = tuple(data) @property def safe_data(self): return deepcopy(list(self._data)) ``` --- #### 7. 替代方案——ThreadLocal 和 DateTimeFormatter 针对某些特定场合,还可以引入 ThreadLocal 技术让每个线程拥有独立副本;或者是选用现代表达形式(如 Java 8 的 DateTimeFormatter)规避传统工具带来的隐患[^4]。 典型应用案例展示如下: ```java // 使用 ThreadLocal 维护 SimpleDateFormat 实例 private static final ThreadLocal<SimpleDateFormat> dateFormatHolder = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd")); public static String formatDate(Date date) { return dateFormatHolder.get().format(date); } // 或者升级至更现代的选择 —— DateTimeFormatter DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String formattedDate = LocalDate.now().format(formatter); ``` --- ### 总结 为了构建健壮可靠的软件系统,开发者应当深入理解各种技术手段的特点,并依据实际情况选取最合适的解决方案。与此同时,始终牢记良好的编码习惯和架构原则也是达成目标不可或缺的一部分。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值