• java并发编程系列二:原子操作/CAS


    什么是原子操作

    不可被中断的一个或者一系列操作

    实现原子操作的方式

    Java可以通过锁和循环CAS的方式实现原子操作

    CAS( Compare And Swap )  为什么要有CAS?

    Compare And Swap就是比较并且交换的一个原子操作,由Cpu在指令级别上进行保证。

    为什么要有CAS:因为通过锁实现原子操作时,其他线程必须等待已经获得锁的线程运行完以后才能获得资源,这样就会占用系统的大量资源

    CAS包含哪些参数?

    CAS包含三个参数:1、变量所在内存地址V;2、变量对应的值A;3、我们将要修改的值B。如果说V上的变量的值是A的话,就用B重新赋值,如果不是A,那就什么事也不做,操作的返回结果原值是多少。

    循环CAS:在一个(死)循环【for(;;)】里不断进行CAS操作,直到成功为止(自旋操作即死循环)。

    CAS实现原子操作的三大问题

    1、 ABA问题:其他的线程把值改成了B,很快改成了A,原子操作的线程发现值是A就修改,这样会有问题。解决ABA,引入版本号:1A-》2C-》3A

    2、 循环时间很长的话,cpu的负荷比较大

    3、 对一个变量进行操作可以,同时操作多个共享变量有点麻烦

    CAS线程安全面试点

    通过硬件层面的阻塞实现原子操作的安全

    原子更新基本类型类

    AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference。

    AtomicInteger的常用方法如下

    ·int addAndGet(int delta): 

    ·boolean compareAndSet(int expect,int update): 

    ·int getAndIncrement(): 原子递增,但是返回的是自增以前的值

    incrementAndGet原子递增,但是返回的是自增以后的值

    ·int getAndSet(int newValue): 

    package com.lgs.atomicint;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * lgs
     * 原子操作更新整型
     */
    public class AtomicIntTest {
        static AtomicInteger ai = new AtomicInteger(1);
        public static void main(String[] args) {
            System.out.println(ai.getAndIncrement());
            ai.incrementAndGet();
            System.out.println(ai.get());
        }
    }

    输出:

    1
    3

    原子更新数组类

    AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray

    AtomicIntegerArray类主要是提供原子的方式更新数组里的整型,

    其常用方法如下。

    ·int addAndGet(int i,int delta): 

    ·boolean compareAndSet(int i,int expect,int update): 

    数组通过构造方法传入,类会将数组复制一份,原数组不会发生变化。

    package com.lgs.atomicarray;
    
    import java.util.concurrent.atomic.AtomicIntegerArray;
    
    /**
     * lgs
     * 原子操作更新数组
     */
    public class AtomicArray {
        static int[] value = new int[]{1,2};
        static AtomicIntegerArray ai = new AtomicIntegerArray(value);
    
        public static void main(String[] args) {
            ai.getAndSet(0,3);
            System.out.println(ai.get(0));
            System.out.println(value[0]);
        }
    
    }

    输出:

    3
    1

    原子更新引用类型提供的类。

    ·AtomicReference: 可以解决更新多个变量的问题

    ·AtomicStampedReference:解决ABA问题 使用数字作为版本 关心得是有几个人改过

    ·AtomicMarkableReference:解决ABA问题 使用Boolean作为版本,关心的是有没有修改过

    package com.lgs;
    
    import java.util.concurrent.atomic.AtomicReference;
    
    /**
     * lgs
     * 原子操作更新引用类型即可以同时更新多个值
     */
    public class AtomicRef {
    
        static AtomicReference<User> userAtomicReference = new AtomicReference<>();
    
        public static void main(String[] args) {
            User user = new User("lgs",26);
            userAtomicReference.set(user);
            User updateUser = new User("ll",27);
            userAtomicReference.compareAndSet(user,updateUser);
            System.out.println(userAtomicReference.get().getName());
            System.out.println(userAtomicReference.get().getOld());
        }
    
        static class User{
            private String name;
            private int old;
    
            public User(String name, int old) {
                this.name = name;
                this.old = old;
            }
    
            public String getName() {
                return name;
            }
    
            public int getOld() {
                return old;
            }
        }
    
    }

    输出:

    ll
    27

    原子更新字段类

    Atomic包提供了以下3个类进行原子字段更新。

    ·AtomicReferenceFieldUpdater: 

    ·AtomicIntegerFieldUpdater: 

    ·AtomicLongFieldUpdater:

    违反了面向对象的原则,一般不使用

  • 相关阅读:
    [转] C# DataTable 导出 Excel 进阶 多行表头、合并单元格、中文文件名乱码
    【转】sql语句精选二
    【转】sqlserver游标概念与实例全面解说
    按多个关键字查询(sql)
    Asp.net使用repeater控件动态添加、删除一行
    SQL SERVER 导入、导出数据到Exce(使用OpenRowset,、OpenDataSource函数)以及访问远程数据库(openrowset/opendatasource/openquery)
    对 Dflying Chen 提到的Edit GridView Using CheckBoxes 进行一个小改造
    软件开发专业技术名词的解释
    (总结)如何为windows服务添加安装程序
    软件开发过程(RUP概述) 转
  • 原文地址:https://www.cnblogs.com/wangzhuxing/p/5207019.html
Copyright © 2020-2023  润新知