Java多线程--原子更新类

原子更新基本类型

    private static ExecutorService fixedThreadPool= Executors.newFixedThreadPool(10);
    private static AtomicInteger atomicInteger=new AtomicInteger(0);

    @Test
    public void test01(){
        for (int i = 0; i < 10; i++) {
            fixedThreadPool.submit(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 1000; j++) {
                        atomicInteger.getAndIncrement();
                    }
                }
            });
        }


        fixedThreadPool.shutdown();
        while (true) {
            if (fixedThreadPool.isTerminated()) {
                break;
            }
        }
        System.out.println("run over atomicInteger="+atomicInteger.get());
    }

原子更新数组

    private static int[] value=new int[]{1,2,3};

    private static AtomicIntegerArray atomicIntegerArray=new AtomicIntegerArray(value);

    /**
     * 原子更新数组
     */
    @Test
    public void test01(){
        int newValue = atomicIntegerArray.addAndGet(0, 3);
        System.out.println("newValue:"+newValue);
    }

原子更新引用

    private static AtomicReference<User> userAtomicReference = new AtomicReference<>();

    /**
     * 原子更新引用类型
     */
    @Test
    public void test03() {
        User user01 = new User(1, "user01");
        userAtomicReference.set(user01);

        User user02 = new User(2, "user02");
        userAtomicReference.compareAndSet(user01, user02);
        System.out.println(userAtomicReference.get().getUserName());
    }

    private static class User {
        private Integer id;

        private String userName;

        public User(Integer id, String userName) {
            this.id = id;
            this.userName = userName;
        }
        //get set
    }

原子更新字段

    private static class User04{

        public volatile int id;

        private String userName;

        public User04(int id, String userName) {
            this.id = id;
            this.userName = userName;
        }
		//get set
    }
    private static AtomicIntegerFieldUpdater<User04> atomicIntegerFieldUpdater=AtomicIntegerFieldUpdater
            .newUpdater(User04.class,"id");
    /**
     * 原子更新字段
     */
    @Test
    public void test04(){
        User04 user04=new User04(1,"user01");
        atomicIntegerFieldUpdater.getAndIncrement(user04);
        System.out.println(atomicIntegerFieldUpdater.get(user04));
    }

原子更新最核心的流程
获取A变量内存偏移量(即在主内存中的地址),传递给Unsafe中的getAndAddInt。
1 getAndAddInt中先通过内存偏移量从主内存中获取数据a,
2 然后将a传递给compareAndSwapInt,compareAndSwapInt将a和内存中的值进行比较,如果相同则将新的值赋给A变量,如果不相同,则继续循环执行1步骤。
在这里插入图片描述
compareAndSwapInt能保证获取值,进行比较,然后赋值是连续的、原子的、不可中断.
CAS
比较当前工作内存中的值和主内存中的值,如果相同则执行规则,问题的关键是比较内存中的值然后执行交换,要保证原子性与连续性、不可中断性。

CAS的缺陷
1 循环时间长,如果CAS失败,会一直进行尝试,如果CAS长时间不成功,会对CPU带来很大的开销。
2 只能保证一个共享变量的原子操作。
3 引入了ABA问题。

//------------------ABA问题演示---------------------
    private static AtomicReference<Integer> integerAtomicReference=new AtomicReference<>(100);
    @Test
    public void test05(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                integerAtomicReference.compareAndSet(100,101);
                integerAtomicReference.compareAndSet(101,100);
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("执行成功否:"+integerAtomicReference.compareAndSet(100,101)+" 结果:"+integerAtomicReference.get());
            }
        }).start();

        while (Thread.activeCount()>2){
        }
    }

线程x从主内存中获取到共享变量z的值A到本地内存中,然后时间片完了,
线程y从主内存获取z的值A,然后更新z的值为B,刷新到主内存中,但是有将z的值改为了A,这样对于A来说相当于没有改动过。
线程x执行CAS执行成功。

解决方案–AtomicStampedReference的引用加版本号

    //---------------------------- ABA问题解决方式AtomicStampedReference--------------------------------
    private static AtomicStampedReference<Integer> integerAtomicStampedReference=new AtomicStampedReference<>(1,1);
    @Test
    public void test06(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                int stamp = integerAtomicStampedReference.getStamp();
                System.out.println("stamp:"+stamp);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                integerAtomicStampedReference.compareAndSet(1,2,1,++stamp);
                integerAtomicStampedReference.compareAndSet(2,1,2,++stamp);
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                int stamp = integerAtomicStampedReference.getStamp();
                System.out.println("stamp:"+stamp);
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                boolean compareResult = integerAtomicStampedReference.compareAndSet(1, 2, stamp, stamp+1);
                System.out.println("compareResult:"+compareResult);
                System.out.println("stamp"+integerAtomicStampedReference.getStamp());
            }
        }).start();
        while (Thread.activeCount()>2){
        }
    }

摘自《Java多线程并发编程艺术》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值