原子操作类Atomic(上)

简介: 原子操作类Atomic

1. 基本类型原子类


AtomicInteger

AtomicBoolean

AtomicLong


1.常用API简介


public final int get() //获取当前的值
public final int getAndSet(int newValue)//获取当前的值,并设置新的值
public final int getAndIncrement()//获取当前的值,并自增
public final int getAndDecrement() //获取当前的值,并自减
public final int getAndAdd(int delta) //获取当前的值,并加上预期的值
boolean compareAndSet(int expect, int update) //如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update)


2.Thread.sleep→CountDownLatch


class MyNumber
{
    AtomicInteger atomicInteger = new AtomicInteger();
    public void addPlusPlus()
    {
        atomicInteger.getAndIncrement();
    }
}
public class AtomicIntegerDemo
{
    public static final int SIZE = 50;
    public static void main(String[] args) throws InterruptedException
    {
        MyNumber myNumber = new MyNumber();
        CountDownLatch countDownLatch = new CountDownLatch(SIZE);
        for (int i = 1; i <=SIZE; i++) {
            new Thread(() -> {
                try {
                    for (int j = 1; j <=1000; j++) {
                        myNumber.addPlusPlus();
                    }
                } finally {
                    countDownLatch.countDown();
                }
            },String.valueOf(i)).start();
        }
        //等待上面50个线程全部计算完成后,再去获得最终值
        //暂停几秒钟线程
        //try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
        countDownLatch.await();
        System.out.println(Thread.currentThread().getName()+"\t"+"result: "+myNumber.atomicInteger.get());
    }
}


2. 数组类型原子类


AtomicIntegerArray

AtomicLongArray

AtomicReferenceArray

public class AtomicIntegerArrayDemo
{
    public static void main(String[] args)
    {
        AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(new int[5]);
        //AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(5);
        //AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(new int[]{1,2,3,4,5});
        for (int i = 0; i <atomicIntegerArray.length(); i++) {
            System.out.println(atomicIntegerArray.get(i));
        }
        System.out.println();
        int tmpInt = 0;
        tmpInt = atomicIntegerArray.getAndSet(0,1122); //下标为0的赋值为1122
        System.out.println(tmpInt+"\t"+atomicIntegerArray.get(0));//获取下标0的值
        tmpInt = atomicIntegerArray.getAndIncrement(0); //下标0的值自增1
        System.out.println(tmpInt+"\t"+atomicIntegerArray.get(0)); //获取下标0的值
        /**
        最后输出结果:
        0
        0
        0
        0
        0
        0 1122
        1122  1123
        */
    }
}


3.引用类型原子类


AtomicReference

@Getter
@ToString
@AllArgsConstructor
class User
{
    String userName;
    int    age;
}
public class AtomicReferenceDemo
{
    public static void main(String[] args)
    {
        User z3 = new User("z3",24);
        User li4 = new User("li4",26);
        AtomicReference<User> atomicReferenceUser = new AtomicReference<>();
        atomicReferenceUser.set(z3);
        System.out.println(atomicReferenceUser.compareAndSet(z3,li4)+"\t"+atomicReferenceUser.get().toString());
        System.out.println(atomicReferenceUser.compareAndSet(z3,li4)+"\t"+atomicReferenceUser.get().toString());
    }
}


自旋锁SpinLockDemo

/**
 * 要求:实现一个自旋锁
 * 自旋锁好处:循环比较获取没有类似wait的阻塞。
 *
 * 通过CAS操作完成自旋锁,A线程先进来调用myLock方法自己持有锁5秒钟,B随后进来后发现
 * 当前有线程持有锁,不是null,所以只能通过自旋等待,直到A释放锁后B随后抢到。
 */
public class SpinLockDemo
{
    AtomicReference<Thread> atomicReference = new AtomicReference<>();
    public void myLock()
    {
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"\t come in");
        while(!atomicReference.compareAndSet(null,thread))
        {
        }
    }
    public void myUnLock()
    {
        Thread thread = Thread.currentThread();
        atomicReference.compareAndSet(thread,null);
        System.out.println(Thread.currentThread().getName()+"\t myUnLock over");
    }
    public static void main(String[] args)
    {
        SpinLockDemo spinLockDemo = new SpinLockDemo();
        new Thread(() -> {
            spinLockDemo.myLock();
            //暂停一会儿线程
            try { TimeUnit.SECONDS.sleep( 5 ); } catch (InterruptedException e) { e.printStackTrace(); }
            spinLockDemo.myUnLock();
        },"A").start();
        //暂停一会儿线程,保证A线程先于B线程启动并完成
        try { TimeUnit.SECONDS.sleep( 1 ); } catch (InterruptedException e) { e.printStackTrace(); }
        new Thread(() -> {
            spinLockDemo.myLock();
            spinLockDemo.myUnLock();
        },"B").start();
    }
}


AtomicStampedReference

携带版本号的引用类型原子类,可以解决ABA问题


解决修改过几次


状态戳原子引用


ABADemo

public class ABADemo
{
    static AtomicInteger atomicInteger = new AtomicInteger(100);
    static AtomicStampedReference atomicStampedReference = new AtomicStampedReference(100,1);
    public static void main(String[] args)
    {
        abaProblem();
        abaResolve();
    }
    public static void abaResolve()
    {
        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println("t3 ----第1次stamp  "+stamp);
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            atomicStampedReference.compareAndSet(100,101,stamp,stamp+1);
            System.out.println("t3 ----第2次stamp  "+atomicStampedReference.getStamp());
            atomicStampedReference.compareAndSet(101,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println("t3 ----第3次stamp  "+atomicStampedReference.getStamp());
        },"t3").start();
        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println("t4 ----第1次stamp  "+stamp);
            //暂停几秒钟线程
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            boolean result = atomicStampedReference.compareAndSet(100, 20210308, stamp, stamp + 1);
            System.out.println(Thread.currentThread().getName()+"\t"+result+"\t"+atomicStampedReference.getReference());
        },"t4").start();
    }
    public static void abaProblem()
    {
        new Thread(() -> {
            atomicInteger.compareAndSet(100,101);
            atomicInteger.compareAndSet(101,100);
        },"t1").start();
        try { TimeUnit.MILLISECONDS.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); }
        new Thread(() -> {
            atomicInteger.compareAndSet(100,20210308);
            System.out.println(atomicInteger.get());
        },"t2").start();
    }
}


AtomicMarkableReference

原子更新带有标记位的引用类型对象

解决是否修改过 (将状态戳简化为true|false),一次性的

状态戳(true/false)原子引用

public class AtomicMarkableReferenceDemo
{
    static AtomicMarkableReference markableReference = new AtomicMarkableReference(100,false);
    public static void main(String[] args)
    {
        new Thread(() -> {
            boolean marked = markableReference.isMarked();
            System.out.println(Thread.currentThread().getName()+"\t"+"默认标识:"+marked);
            //暂停1秒钟线程,等待后面的T2线程和我拿到一样的模式flag标识,都是false
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            markableReference.compareAndSet(100,1000,marked,!marked);
        },"t1").start();
        new Thread(() -> {
            boolean marked = markableReference.isMarked();
            System.out.println(Thread.currentThread().getName()+"\t"+"默认标识:"+marked);
            try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
            boolean b = markableReference.compareAndSet(100, 2000, marked, !marked);
            System.out.println(Thread.currentThread().getName()+"\t"+"t2线程CASresult: "+b);
            System.out.println(Thread.currentThread().getName()+"\t"+markableReference.isMarked());
            System.out.println(Thread.currentThread().getName()+"\t"+markableReference.getReference());
        },"t2").start();
    }
}
/**
 *  CAS----Unsafe----do while+ABA---AtomicStampedReference,AtomicMarkableReference
 *
 *  AtomicStampedReference,version号,+1;
 *
 *  AtomicMarkableReference,一次,false,true
 *
 */


4.对象的属性修改原子类


AtomicIntegerFieldUpdater

原子更新对象中int类型字段的值

AtomicLongFieldUpdater

原子更新对象中Long类型字段的值

AtomicReferenceFieldUpdater

原子更新引用类型字段的值


1.使用目的


以一种线程安全的方式操作非线程安全对象内的某些字段


2.使用要求


更新的对象属性必须使用 public volatile 修饰符。


因为对象的属性修改类型原子类都是抽象类,所以每次使用都必须使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。


3.AtomicIntegerFieldUpdaterDemo


//资源类
class BankAccount {
    String bankName = "CCB";
    //更新的对象属性必须使用 public volatile 修饰符。
    public volatile int money = 0;//钱数
    public void add() //synchronized锁方式
    {
        money++;
    }
    //因为对象的属性修改类型原子类都是抽象类,所以每次使用都必须
    // 使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。
    AtomicIntegerFieldUpdater<BankAccount> fieldUpdater =
            AtomicIntegerFieldUpdater.newUpdater(BankAccount.class, "money");
    //不加synchronized,保证高性能原子性,局部微创小手术
    //参数:对哪个对象操作
    public void transMoney(BankAccount bankAccount) {
        fieldUpdater.getAndIncrement(bankAccount);
    }
}
/**
 * 以一种线程安全的方式操作非线程安全对象的某些字段。
 * <p>
 * 需求:
 * 10个线程,
 * 每个线程转账1000,
 * 不使用synchronized,尝试使用AtomicIntegerFieldUpdater来实现。
 */
public class AtomicIntegerFieldUpdaterDemo {
    public static void main(String[] args) throws InterruptedException {
        BankAccount bankAccount = new BankAccount();
        CountDownLatch countDownLatch = new CountDownLatch(10);
        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                try {
                    for (int j = 1; j <= 1000; j++) {
                        //bankAccount.add(); synchronized锁方式
                        bankAccount.transMoney(bankAccount);
                    }
                } finally {
                    countDownLatch.countDown();
                }
            }, String.valueOf(i)).start();
        }
        countDownLatch.await();
        System.out.println(Thread.currentThread().getName() + "\t" + "result: " + bankAccount.money);
    }
}


4.AtomicReferenceFieldUpdater


//资源类
class MyVar 
{
    public volatile Boolean isInit = Boolean.FALSE;
    AtomicReferenceFieldUpdater<MyVar,Boolean> referenceFieldUpdater =
            AtomicReferenceFieldUpdater.newUpdater(MyVar.class,Boolean.class,"isInit");
    public void init(MyVar myVar)
    {
        if (referenceFieldUpdater.compareAndSet(myVar,Boolean.FALSE,Boolean.TRUE))
        {
            System.out.println(Thread.currentThread().getName()+"\t"+"----- start init,need 2 seconds");
            //暂停几秒钟线程
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(Thread.currentThread().getName()+"\t"+"----- over init");
        }else{
            System.out.println(Thread.currentThread().getName()+"\t"+"----- 已经有线程在进行初始化工作。。。。。");
        }
    }
}
/**
 * 需求:
 * 多线程并发调用一个类的初始化方法,如果未被初始化过,将执行初始化工作,
 * 要求只能被初始化一次,只有一个线程操作成功
 */
public class AtomicReferenceFieldUpdaterDemo
{
    public static void main(String[] args)
    {
        MyVar myVar = new MyVar();
        for (int i = 1; i <=5; i++) {
            new Thread(() -> {
                myVar.init(myVar);
            },String.valueOf(i)).start();
        }
    }
}
/**
输出结果:
2 ----- start init,need 2 seconds
1 ----- 已经有线程在进行初始化工作。。。。。
4 ----- 已经有线程在进行初始化工作。。。。。
3 ----- 已经有线程在进行初始化工作。。。。。
5 ----- 已经有线程在进行初始化工作。。。。。
2 ----- over init
总结:多线程环境下,存在并发情况,实际执行结果并不一定是线程1抢到初始化,每次都是不确定的。使用AtomicReferenceFieldUpdater可以保证有且只有一次初始化执行
*/


5.你在哪里用了volatile


AtomicReferenceFieldUpdater(相当有含金量的回答)


5.原子操作增强类原理深度解析


Java8新特性


DoubleAccumulator

DoubleAdder

LongAccumulator

LongAdder

1673415803616.jpg

1673415813575.jpg

1.模拟点赞计数器,查看性能


1673415823302.jpg

LongAdder只能用来计算加法,且从零开始计算


LongAccumulator提供了自定义的函数操作

public class LongAdderAPIDemo
{
    public static void main(String[] args)
    {
        LongAdder longAdder = new LongAdder();
        longAdder.increment(); //自增1
        longAdder.increment();//自增1
        longAdder.increment();//自增1
        System.out.println(longAdder.sum()); //3
        LongAccumulator longAccumulator = new LongAccumulator(new LongBinaryOperator()
        {
            @Override
            public long applyAsLong(long left, long right)
            {
                return left + right;//可以自定义加减乘除,各种计算
            }
        },0); //可以自定义初始值
        longAccumulator.accumulate(1);//1
        longAccumulator.accumulate(3);//4
        System.out.println(longAccumulator.get());
    }
}
相关文章
|
6月前
|
算法 程序员 C语言
C/C++原子操作与atomic CAS底层实现原理
假定有两个操作A 和B,如果从执行A 的线程来看,当另一个线程执行B 时,要么将B 全部执行完,要么完全不执行B,那么A 和B 对彼此来说是原子的。
476 1
C/C++原子操作与atomic CAS底层实现原理
|
缓存 调度
Atomic 类
Atomic 类
64 0
|
5月前
|
安全 前端开发 Java
并发编程之原子操作Atomic&Unsafe
并发编程之原子操作Atomic&Unsafe
|
2月前
|
存储 安全 C++
C++ 原子变量atomic variable
原子变量是 C++11 引入的一种同步机制,用于多线程环境中的无锁、线程安全操作。其操作不可分割,避免了数据竞争和不一致问题。原子变量位于 `&lt;atomic&gt;` 头文件中,支持多种类型如 `std::atomic&lt;T&gt;` 和特化类型。基本用法包括定义原子变量、加载、存储、交换及比较交换操作。内存顺序(如 `std::memory_order_seq_cst`)用于控制内存访问顺序和可见性,适用于不同场景。原子变量常用于线程安全的计数器和标志位等。
|
3月前
|
安全 Go API
go语言中的Atomic操作与sema锁
在并发编程中,确保数据一致性和程序正确性是关键挑战。Go语言通过协程和通道提供强大支持,但在需精细控制资源访问时,Atomic操作和sema锁变得至关重要。Atomic操作确保多协程环境下对共享资源的访问是不可分割的,如`sync/atomic`包中的`AddInt32`等函数,底层利用硬件锁机制实现。sema锁(信号量锁)控制并发协程数量,其核心是一个uint32值,当大于零时通过CAS操作实现锁的获取与释放;当为零时,sema锁管理协程休眠队列。这两种机制共同保障了Go语言并发环境下的数据完整性和程序稳定性。
|
3月前
|
安全 Java API
Java多线程编程:使用Atomic类实现原子操作
在Java多线程环境中,共享资源的并发访问可能导致数据不一致。传统的同步机制如`synchronized`关键字或显式锁虽能保障数据一致性,但在高并发场景下可能导致线程阻塞和性能下降。为此,Java提供了`java.util.concurrent.atomic`包下的原子类,利用底层硬件的原子操作确保变量更新的原子性,实现无锁线程安全。
32 0
|
4月前
|
安全 Oracle Java
(四)深入理解Java并发编程之无锁CAS机制、魔法类Unsafe、原子包Atomic
其实在我们上一篇文章阐述Java并发编程中synchronized关键字原理的时候我们曾多次谈到过CAS这个概念,那么它究竟是什么?
107 1
|
6月前
|
安全 Java vr&ar
Atomic原子类总结
Atomic原子类总结
|
安全 Java API
原子操作类解读
原子操作类解读
原子操作类解读
|
缓存 安全 Java
Java并发编程中的四个关键字:ThreadLocal、Volatile、Synchronized和Atomic
Java并发编程中的四个关键字:ThreadLocal、Volatile、Synchronized和Atomic
267 0