原子操作类的使用

参考文章:https://blog.csdn.net/tlk20071/article/details/75729675

一、自增:不加锁线程不安全

public class AtomicDemo {
    //定义一个共享变量
    private int value;
 
    //获取共享变量
    public int getValue() {
        return value;
    }

    //为共享变量设置新值
    public void setValue(int value) {
        this.value = value;
    }

    public static void main(String[] args) throws InterruptedException {
        //创建一个有共享变量的对象
        AtomicDemo demo = new AtomicDemo();
        //创建线程A、B
        ThreadA threadA = new ThreadA(demo);
        ThreadB threadB = new ThreadB(demo);
        //启动线程A、B
        threadA.start();
        threadB.start();
        //主函数等待运行结束
        threadA.join();
        threadB.join();
        //获取运算结果
        System.out.println(demo.getValue());

    }
}

class ThreadA extends Thread {
    private AtomicDemo demo;
    public ThreadA(AtomicDemo demo) {
        this.demo = demo;
    }

    @Override
    public void run() {
        //任务是为demo的value变量自增十万次
        for (int i = 0; i < 100000; i++) {
            demo.setValue(demo.getValue()+1);
        }

    }
}

class ThreadB extends Thread {
    private AtomicDemo demo;
    public ThreadB(AtomicDemo demo) {
        this.demo = demo;
    }

    @Override
    public void run() {
        //任务是为demo的value变量自增十万次
        for (int i = 0; i < 100000; i++) {
            demo.setValue(demo.getValue()+1);
        }
    }
}

运行结果:150450

        上述代码的运行结果说明,value变量线程不安全。一般的做法是,让线程A与线程B共享一个同步锁。

 

二、无锁:使用CAS操作 原子更新基本类型

         

import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by Jay.Zhou on 2018/9/13.
 */
public class AtomicDemo {
    //共享变量用原子操作类
    private AtomicInteger integer;

    public AtomicDemo() {
        integer = new AtomicInteger(0);
    }

    public AtomicInteger getInteger() {
        return integer;
    }

    public void setInteger(AtomicInteger integer) {
        this.integer = integer;
    }

    public static void main(String[] args) throws InterruptedException {
        //创建一个有共享变量的对象
        AtomicDemo demo = new AtomicDemo();
        //创建线程A、B
        ThreadA threadA = new ThreadA(demo);
        ThreadB threadB = new ThreadB(demo);
        //启动线程A、B
        threadA.start();
        threadB.start();
        //主函数等待运行结束
        threadA.join();
        threadB.join();
        //获取运算结果
        System.out.println(demo.getInteger());

    }
}

class ThreadA extends Thread {
    private AtomicDemo demo;

    public ThreadA(AtomicDemo demo) {
        this.demo = demo;
    }

    @Override
    public void run() {
        //任务是为demo的共享变量自增十万次
        for (int i = 0; i < 100000; i++) {
            //CAS操作自增
            demo.getInteger().incrementAndGet();
        }

    }
}

class ThreadB extends Thread {
    private AtomicDemo demo;

    public ThreadB(AtomicDemo demo) {
        this.demo = demo;
    }

    @Override
    public void run() {
        //任务是为demo的共享变量自增十万次
        for (int i = 0; i < 100000; i++) {
            //CAS操作自增
            demo.getInteger().incrementAndGet();
        }
    }
}

运行结果:200000

        使用CAS操作的原子操作类,线程安全,不用加锁

三、无锁:使用CAS操作 原子更新引用类型

import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * Created by Jay.Zhou on 2018/9/13.
 */
public class AtomicStrampReferenceDemo {
    public static void main(String[] args) throws InterruptedException {
        User A = new User();
        User B = new User();

        //默认的原子操作类的对象是 A,版本为1
        AtomicStampedReference<User> reference = new AtomicStampedReference<User>(A, 1);
        for (int i = 0; i < 10; i++) {
            //开启是个线程,如果是预期版本,则操作reference内部维护的对象
            new Thread(() -> {
                /**
                 * V   expectedReference,   就是你提供的对象 CAS(V,E,N)的E
                   V   newReference,        如果 E == V ,那么把 这个新的引用赋值给 共享变量
                   int expectedStamp,       你提供的版本号
                   int newStamp             你提供的版本号如果与共享变量的版本号一致,那么把这个新的版本号赋值给共享变量版本号
                 */
                //第一个与第三个参数,A1,拿去与reference的构造函数中的共享变量比较
                //如果比较一致,返回true,并且将内部的数据设置为 B2
                if (reference.compareAndSet(A, B, 1, 2)) {
                    System.out.println("user版本升级");
                }
            }).start();
        }
        //等待设置结束
        Thread.sleep(2000);
        //获取版本号为2的User对象
        User C = reference.get(new int[]{2});
        //比较是否是同一个对象
        System.out.println(C == B);

    }
}

class User {
}
/**
 user版本升级
 true
 */

 

四、原子更新引用类型

import java.util.concurrent.atomic.AtomicReference;
 
public class AtomicReferenceTest {
    public static AtomicReference<User> atomicUserRef = new AtomicReference<User>();
 
    public static void main(String[] args) {
        User user = new User("测试1", 10);
        atomicUserRef.set(user);
        User updateUser = new User("测试2", 22);
        atomicUserRef.compareAndSet(user, updateUser);
        System.out.println(atomicUserRef.get().getName());
        System.out.println(atomicUserRef.get().getPassword());
    }
 
    static class User {
        private String name;
        private int password;
        //..
    }
}

测试2
22

 

五、原子更新字段类型

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
 
public class AtomicIntegerFieldUpdaterTest {
    // 创建原子更新器,并设置需要更新的对象类和对象的属性
    private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");
 
    public static void main(String[] args) {
        // 设置柯南的年龄是10岁
        User conan = new User("conan", 10);
        // 柯南长了一岁,但是仍然会输出旧的年龄
        System.out.println(a.getAndIncrement(conan));
        // 输出柯南现在的年龄
        System.out.println(a.get(conan));
    }
 
    public static class User {
        private String name;
        public volatile int old;
 
        public User(String name, int old) {
            this.name = name;
            this.old = old;
        }
 
        public String getName() {
            return name;
        }
 
        public int getOld() {
            return old;
        }
    }
}

 

六、原子更新数组类型

 

 

import java.util.Arrays;
import java.util.concurrent.atomic.AtomicIntegerArray;


public class AtomicReferenceTest {


    private static int[] value = new int[]{1, 2, 3, 4, 5};
    private static AtomicIntegerArray atomic =
            new AtomicIntegerArray(value);

    public static void main(String[] args) {
        atomic.getAndSet(2, 100);
        System.out.println(Arrays.toString(value));//[1, 2, 3, 4, 5] 原来的不改动
        System.out.println(atomic.toString());//[1, 2, 100, 4, 5]
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小大宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值