多线程-Java原子变量-java.util.concurrent.atomic.*

转载地址:http://blog.csdn.net/a19881029/article/details/8202933

一个没有并发控制的计数器:

[java]  view plain copy
  1. public class Counter implements Runnable {  
  2.     private static int count;  
  3.       
  4.     public void run() {  
  5.         System.out.println(Thread.currentThread().getName()   
  6.                 + ":" + (++count));  
  7.     }  
  8.       
  9.     public static void main(String[] args){  
  10.         Counter counter = new Counter();  
  11.         Thread t1 = new Thread(counter);  
  12.         Thread t2 = new Thread(counter);  
  13.         Thread t3 = new Thread(counter);  
  14.         Thread t4 = new Thread(counter);  
  15.         t1.start();  
  16.         t2.start();  
  17.         t3.start();  
  18.         t4.start();  
  19.     }  
  20. }  

有时运行正常,但是偶尔会出现如下运行结果:

[plain]  view plain copy
  1. Thread-1:2  
  2. Thread-0:1  
  3. Thread-2:3  
  4. Thread-3:3  

这显然和预期结果不太一样,先用javap -verbose命令分析一下这个类,在字节码层面上,++count等价于虚拟机顺次执行如下5条字节码指令(不考虑运行期的优化)

[plain]  view plain copy
  1. getstatic  获取指定类的静态域,并将其值压入栈顶  
  2. iconst_1   将int型1推送至栈顶  
  3. iadd       将栈顶两int型数值相加并将结果压入栈顶  
  4. dup        复制栈顶数值并将复制值压入栈顶  
  5. putstatic  为指定类的静态域赋值  

当Thread-3线程执行getstatic指令时,Thread-2线程还未执行至iadd指令,故Thread-3线程获取的初始静态域count的值和Thread-2线程一样,都为2

本质原因就是++count虽然只是一行代码,但这一过程并非原子操作

要保证这种类型的原子操作,可以使用java.util.concurrent.atomic包下的类

[plain]  view plain copy
  1. 软件包 java.util.concurrent.atomic   
  2. 类的小工具包,支持在单个变量上解除锁的线程安全编程。  

示例如下:

[java]  view plain copy
  1. public class Counter implements Runnable {  
  2.     private final AtomicInteger count = new AtomicInteger(0);  
  3.       
  4.     public void run() {  
  5.         System.out.println(Thread.currentThread().getName()   
  6.                 + ":" + count.incrementAndGet());  
  7.     }  
  8.       
  9.     public static void main(String[] args){  
  10.         Counter counter = new Counter();  
  11.         Thread t1 = new Thread(counter);  
  12.         Thread t2 = new Thread(counter);  
  13.         Thread t3 = new Thread(counter);  
  14.         Thread t4 = new Thread(counter);  
  15.         t1.start();  
  16.         t2.start();  
  17.         t3.start();  
  18.         t4.start();  
  19.     }  
  20. }  

看看源代码中究竟是如何实现的

[java]  view plain copy
  1. private volatile int value;  
  2.   
  3. public AtomicInteger(int initialValue) {  
  4.     value = initialValue;  
  5. }  
  6.   
  7. public final int incrementAndGet() {  
  8.     for (;;) {  
  9.         int current = get();  
  10.         int next = current + 1;  
  11.         if (compareAndSet(current, next))  
  12.             return next;  
  13.     }  
  14. }  
  15.   
  16. /** 
  17.     * Atomically sets the value to the given updated value 
  18.     * if the current value {@code ==} the expected value. 
  19.     * 
  20.     * @param expect the expected value 
  21.     * @param update the new value 
  22.     * @return true if successful. False return indicates that 
  23.     * the actual value was not equal to the expected value. 
  24.     */  
  25. public final boolean compareAndSet(int expect, int update) {  
  26.     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
  27. }  
  28.       
  29. public final int get() {  
  30.   return value;  
  31. }  

是不是和乐观锁很像,如果结果符合预期结果,就将结果返回,否则不断进行重试,并没有进行同步,兼顾了安全性和性能

java.util.concurrent.atomic包下还有很多类,使用这些类可以保证对这些类的诸如“获取-更新”操作是原子性的,从而避发生竞态条件

[plain]  view plain copy
  1. AtomicBoolean 可以用原子方式更新的 boolean 值。   
  2. AtomicInteger 可以用原子方式更新的 int 值。   
  3. AtomicIntegerArray 可以用原子方式更新其元素的 int 数组。   
  4. AtomicIntegerFieldUpdater<T> 基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新。   
  5. AtomicLong 可以用原子方式更新的 long 值。   
  6. AtomicLongArray 可以用原子方式更新其元素的 long 数组。   
  7. AtomicLongFieldUpdater<T> 基于反射的实用工具,可以对指定类的指定 volatile long 字段进行原子更新。   
  8. AtomicMarkableReference<V> AtomicMarkableReference 维护带有标记位的对象引用,可以原子方式对其进行更新。   
  9. AtomicReference<V> 可以用原子方式更新的对象引用。   
  10. AtomicReferenceArray<E> 可以用原子方式更新其元素的对象引用数组。   
  11. AtomicReferenceFieldUpdater<T,V> 基于反射的实用工具,可以对指定类的指定 volatile 字段进行原子更新。   
  12. AtomicStampedReference<V> AtomicStampedReference 维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。   
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的`java.util.concurrent.atomic.AtomicReference`提供了一种线程安全的方式来更新对象引用。它通过使用CAS(Compare-And-Swap)算法实现了原子性的操作。 下面是一个简单的案例,展示如何使用`AtomicReference`类: ```java import java.util.concurrent.atomic.AtomicReference; public class AtomicReferenceExample { public static void main(String[] args) { // 初始化AtomicReference对象 AtomicReference<String> atomicReference = new AtomicReference<>("Hello"); // 获取当前对象引用的值 String currentValue = atomicReference.get(); System.out.println("Current value: " + currentValue); // 比较并替换 boolean updated = atomicReference.compareAndSet("Hello", "World"); System.out.println("Value updated: " + updated); // 获取更新后的值 String updatedValue = atomicReference.get(); System.out.println("Updated value: " + updatedValue); } } ``` 在上面的示例中,我们首先创建了一个`AtomicReference`对象,并初始化为字符串`"Hello"`。然后我们使用`compareAndSet`方法比较当前对象引用的值是否为`"Hello"`,如果是,则将其替换为`"World"`。最后,我们获取更新后的值,并输出到控制台。 需要注意的是,`AtomicReference`类提供了许多其他有用的方法,如`set`、`getAndSet`、`weakCompareAndSet`等,可以根据具体的需求选择使用。 总之,`AtomicReference`类是Java中一种非常有用的线程安全对象引用类,可以避免多个线程同时修改对象引用时出现的竞争条件问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值