多线程:原子类

2020-02-01  本文已影响0人  JBryan
1.什么是原子类

原子类:一度认为原子是不可分割的最小单位,故原子类可以认为其操作都是不可分割。
对多线程访问同一个变量,我们需要加锁,而锁是比较消耗性能的,JDk1.5之后,​ 新增的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式,​ 这些类同样位于JUC包下的atomic包下,发展到JDk1.8,该包下共有17个类,​ 囊括了原子更新基本类型、原子更新数组、原子更新属性、原子更新引用。
1.8新增的原子类:DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder、Striped64

2.原子更新基本类型

大致可以归为3类:
AtomicBoolean、AtomicInteger、AtomicLong 元老级的原子更新,方法几乎一模一样​。
DoubleAdder、LongAdder 对Double、Long的原子更新性能进行优化提升​ 。
DoubleAccumulator、LongAccumulator 支持自定义运算。
AtomicInteger使用

package com.ljessie.sinopsis.atomic;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 原子的Integer型
 * @author zbw
 *
 */
public class AtomicIntegerDemo {
    
    private static AtomicInteger num = new AtomicInteger(0);
    
    public static void increate() {
        num.incrementAndGet();
    }
    
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread() {
                public void run() {
                    for (int j = 0; j < 10; j++) {
                        try {
                            increate();
                            System.out.println(num);
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        
                    }
                }
            }.start();
        }
    }
}

LongAccumulator 使用

package com.ljessie.sinopsis.atomic;

import java.util.concurrent.atomic.LongAccumulator;
import java.util.function.LongBinaryOperator;

/**
 * JDK1.8之后的原子Long型
 * @author zbw
 *
 */
public class LongAccumlatorDemo {

    public static void main(String[] args) {
        //输入一个数字,如果比上一个输入的大,则直接返回,如果输入的小,则返回上一个.
        LongAccumulator la = new LongAccumulator(new LongBinaryOperator() {
            
            @Override
            public long applyAsLong(long left, long right) {
                
                return left>right?left:right;
            }
        }, 5);
        
        la.accumulate(3);
        System.out.println(la.get());
        la.accumulate(7);
        System.out.println(la.get());
    }
}
3.原子更新数组类型

AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray,使用方法类似
AtomicIntegerArray使用

package com.ljessie.sinopsis.atomic;

import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.function.IntBinaryOperator;

/**
 * 原子的更新数组
 * @author zbw
 *
 */
public class AtomicIntegerArrayDemo {
    
    public static void main(String[] args) {
        int[] arr = {1,3,5,7,9};
        AtomicIntegerArray array = new AtomicIntegerArray(arr);
        int i = array.addAndGet(0, 3);
        System.out.println(i);
        
        int j = array.accumulateAndGet(4, 10, new IntBinaryOperator() {
            
            @Override
            public int applyAsInt(int left, int right) {
                //将10和数组下标为4的值进行对比,a[4]是left,10是right
                return left>right?left:right;
            }
        });
        
        System.out.println(j);
    }

}

4.原子更新属性
原子地更新某个类里的某个字段时,就需要使用原子更新字段类,Atomic包提供了以下4个类进行原子字段更新​ AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedReference、AtomicReferenceFieldUpdater

package com.ljessie.sinopsis.atomic;

import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
 * 原子属性
 * @author zbw
 *
 */
public class AtomicLongFieldUpdaterDemo {
    
    
    public static void main(String[] args) {
        AtomicLongFieldUpdater<Student> updater = AtomicLongFieldUpdater.newUpdater(Student.class, "id");
        
        Student student = new Student(1, "zbw");
        updater.compareAndSet(student, 1, 1000);
        System.out.println(student.getId());
        
        AtomicReferenceFieldUpdater<Student , String> referenceUpdater = 
                AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class, "name");
        boolean isSuccess = referenceUpdater.compareAndSet(student, "zbw", "jessie");
        if(isSuccess) {
            System.out.println(student.getName());
        }
    }
    
    
}
class Student{
    volatile long id;
    volatile String name;
    public Student(long id,String name){
        this.id = id;
        this.name = name;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }   
}

使用上述类的时候,必须遵循以下原则
字段必须是volatile类型的,在线程之间共享变量时保证立即可见
字段的描述类型是与调用者与操作对象字段的关系一致。
也就是说调用者能够直接操作对象字段,那么就可以反射进行原子操作。
对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。
只能是实例变量,不能是类变量,也就是说不能加static关键字。
只能是可修改变量,不能使final变量,因为final的语义就是不可修改。
对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段,不能修改其包装类型(Integer/Long)。
如果要修改包装类型就需要使用AtomicReferenceFieldUpdater。

5.原子更新引用

AtomicReference的使用

package com.ljessie.sinopsis.atomic;

import java.util.concurrent.atomic.AtomicReference;

/**
 * 原子的引用修改
 * @author zbw
 *
 */
public class AtomicReferenceDemo {

    
    public static void main(String[] args) {
        AtomicReference<Students> reference = new AtomicReference<Students>();
        Students student1 = new Students(1, "zbw");
        Students student2 = new Students(2, "jessie");
        reference.set(student1);
        reference.compareAndSet(student1, student2);
        Students student3 = reference.get();
        System.out.println(student3.getName());
    }
}

class Students{
    private long id;
    private String name;
    public Students(long id,String name){
        this.id = id;
        this.name = name;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
}
上一篇 下一篇

猜你喜欢

热点阅读