【并发技术09】原子性操作类的使用

简介: 【并发技术09】原子性操作类的使用

在 java5 以后,我们接触到了线程原子性操作,也就是在修改时我们只需要保证它的那个瞬间是安全的即可,经过相应的包装后可以再处理对象的并发修改,本文总结一下 Atomic 系列的类的使用方法,其中包含:

def67a655289e1c01f97b1a807c03c36_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


1. 基本类型的使用


首先看一下 AtomicInteger 的使用,AtomicInteger 主要是针对整数的修改的,看一下示例代码:

public class AtomicIntegerDemo {
    public final static AtomicInteger TEST_INTEGER = new AtomicInteger(1);
    public static void main(String []args) {
         for(int i = 0 ; i < 10 ; i++) { //开启10个线程
             new Thread() {
                 public void run() {
                     try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    int now = TEST_INTEGER.incrementAndGet(); //自增
                    System.out.println(Thread.currentThread().getName() + " get value : " + now);
                 }
             }.start();
         }
    }
}


来看一下结果:

Thread-3 get value : 4

Thread-7 get value : 5

Thread-9 get value : 9

Thread-4 get value : 6

Thread-0 get value : 3

Thread-1 get value : 8

Thread-5 get value : 11

Thread-8 get value : 7

Thread-2 get value : 10

Thread-6 get value : 2

可以看出,10 个线程之间是线程安全的,并没有冲突。也就是说,我们使用原子性操作类去操作基本类型 int 就可以解决线程安全问题,一个线程在操作的时候,会对其它线程进行排斥,不用我们手动去使用 synchronized 实现互斥操作了。AtomicLong 和 AtomicBoolean 类似,就不举例子了。


2. 数组类型的使用


下面要开始说 Atomic 的数组用法,Atomic 的数组要求不允许修改长度等,不像集合类那么丰富的操作,不过它可以让数组上每个元素的操作绝对安全的,也就是它细化的力度还是到数组上的元素,做了二次包装,虽然是数组类型的,但是最后还是操作数组中存的数,所以会了上面的基本类型的话,数组类型也很好理解。这里主要看一下 AtomicIntegerArray 的使用,其它的类似。

public class AtomicIntegerArrayTest {
    private final static AtomicIntegerArray ATOMIC_INTEGER_ARRAY = new AtomicIntegerArray(new int[]{1,2,3,4,5,6,7,8,9,10}); 
    public static void main(String []args) throws InterruptedException {
        Thread []threads = new Thread[10];
        for(int i = 0 ; i < 10 ; i++) {
            final int index = i;
            final int threadNum = i;
            threads[i] = new Thread() {
                public void run() {
                    int result = ATOMIC_INTEGER_ARRAY.addAndGet(index, index + 1);
                    System.out.println("线程编号为:" + threadNum + " , 对应的原始值为:" + (index + 1) + ",增加后的结果为:" + result);
                }
            };
            threads[i].start();
        }
        for(Thread thread : threads) {
            thread.join();
        }
        System.out.println("=========================>\n执行已经完成,结果列表:");
        for(int i = 0 ; i < ATOMIC_INTEGER_ARRAY.length() ; i++) {
            System.out.println(ATOMIC_INTEGER_ARRAY.get(i));
        }
    }
}

运行结果是给每个数组元素加上相同的值,它们之间互不影响。


3. 作为类属性的使用


当某个数据类型是某个类中的一个属性的时候,然后我们要操作该数据,就需要使用属性原子修改器了,这里还是以 Integer 为例,即:AtomicIntegerFieldUpdater。示例代码如下:

public class AtomicIntegerFieldUpdaterTest {    
    static class A {  
        volatile int intValue = 100;  
    }        
    public final static AtomicIntegerFieldUpdater<A> ATOMIC_INTEGER_UPDATER = AtomicIntegerFieldUpdater.newUpdater(A.class, "intValue");        
    public static void main(String []args) {  
        final A a = new A();  
        for(int i = 0 ; i < 10 ; i++) {  
            new Thread() {  
                public void run() {  
                    if(ATOMIC_INTEGER_UPDATER.compareAndSet(a, 100, 120)) {  
                        System.out.println(Thread.currentThread().getName() + " 对对应的值做了修改!");  
                    }  
                }  
            }.start();  
        }  
    }  
}

可以看到,这里需要将类和类属性传进去才行,传进去后其实跟前面操作 Integer 没什么不同了,本质都一样的,运行一下,结果只有一个线程能对其进行修改。

线程的原子性操作类的使用就简单总结到这,其他的操作类原理都相似,可以参考 JDK 的文档,可以很容易写出相应的测试代码。


相关文章
|
12天前
|
缓存 安全 Java
多线程的三大特性:原子性、可见性和有序性
多线程的三大特性:原子性、可见性和有序性
16 0
|
4月前
|
调度 数据库 数据库管理
数据库事务中调度串行化、冲突可串行化、前趋图(优先图)
数据库事务中调度串行化、冲突可串行化、前趋图(优先图)
107 0
|
4月前
|
Java
8.volatile为啥不能保证原子性?
8.volatile为啥不能保证原子性?
29 0
8.volatile为啥不能保证原子性?
|
8月前
|
安全 Java
架构系列——面试必问:volatile的可见性、防止指令重排序以及不能保证原子性的解决方式
架构系列——面试必问:volatile的可见性、防止指令重排序以及不能保证原子性的解决方式
|
9月前
volatile 的作用是什么?能保证原子性吗?能保证有序性吗?
volatile 的作用是什么?能保证原子性吗?能保证有序性吗?
70 0
|
10月前
|
SQL Java easyexcel
多线程事务如何保证效率和原子性
多线程事务如何保证效率和原子性
165 0
|
11月前
|
SQL 存储 Oracle
精通Java事务编程(3)-弱隔离级别之快照隔离和可重复读
表面看,RC已满足事务所需的一切特征:支持中止(原子性),防止读取不完整的事务结果,并防止并发写的混乱。这点很关键!为我们的开发省去一大堆麻烦。
92 0
|
缓存 Java 中间件
并发三大特性——可见性
并发三大特性——可见性
156 0
并发三大特性——可见性
|
SQL Oracle 关系型数据库
原子性和一致性的区别
原子性和一致性的区别
886 0
|
Java
【Java 并发编程】线程操作原子性问题 ( 问题业务场景分析 | 使用 synchronized 解决线程原子性问题 )
【Java 并发编程】线程操作原子性问题 ( 问题业务场景分析 | 使用 synchronized 解决线程原子性问题 )
133 0
【Java 并发编程】线程操作原子性问题 ( 问题业务场景分析 | 使用 synchronized 解决线程原子性问题 )

热门文章

最新文章

相关实验场景

更多