Java AtomicInteger的用法

作者: java欧阳丰 | 来源:发表于2019-07-13 14:30 被阅读3次

    1、java.util.concurrent.atomic 的包里有AtomicBoolean, AtomicInteger,AtomicLong,AtomicLongArray,
    AtomicReference等原子类的类,主要用于在高并发环境下的高效程序处理,来帮助我们简化同步处理.

    在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。

    2、AtomicInteger的基本方法

    • 创建一个AtomicInteger
      System.out.println(atomicInteger.get());
    
    
    --->输出 : 123
    
    • 创建一个不传值的,默认值为0
      AtomicInteger atomicInteger = new AtomicInteger();
      System.out.println(atomicInteger.get());
    ---->输出: 0
    
    • 获取和赋值
    atomicInteger.get(); //获取当前值
    atomicInteger.set(999); //设置当前值
    

    atomicInteger.compareAndSet(expectedValue,newValue)

     public static void main(String[] args) {
            AtomicInteger atomicInteger = new AtomicInteger(0);
            System.out.println(atomicInteger.get());
    
            int expectedValue = 123;
            int newValue      = 234;
            Boolean b =atomicInteger.compareAndSet(expectedValue, newValue);
            System.out.println(b);
            System.out.println(atomicInteger);
    
        }
    
    ----》输出结果为: 0 false 0
    
    
     public static void main(String[] args) {
            AtomicInteger atomicInteger = new AtomicInteger(123);
            System.out.println(atomicInteger.get());
    
            int expectedValue = 123;
            int newValue      = 234;
            Boolean b =atomicInteger.compareAndSet(expectedValue, newValue);
            System.out.println(b);
            System.out.println(atomicInteger);
    
        }
    
    -----》输出结果为: 123 true  234
    

    由上可知该方法表示,atomicInteger的值与expectedValue相比较,如果不相等,则返回false,
    atomicInteger原有值保持不变;如果两者相等,则返回true,atomicInteger的值更新为newValue

    • getAndAdd()方法与AddAndGet方法
           AtomicInteger atomicInteger = new AtomicInteger(123);
            System.out.println(atomicInteger.get());  --123
    
            System.out.println(atomicInteger.getAndAdd(10)); --123 获取当前值,并加10
            System.out.println(atomicInteger.get()); --133
    
    
            System.out.println(atomicInteger.addAndGet(10)); --143 获取加10后的值,先加10
            System.out.println(atomicInteger.get()); --143
    
    • getAndDecrement()和DecrementAndGet()方法
            AtomicInteger atomicInteger = new AtomicInteger(123);
            System.out.println(atomicInteger.get());   --123
    
            System.out.println(atomicInteger.getAndDecrement()); --123 获取当前值并自减
            System.out.println(atomicInteger.get());  --122
    
    
            System.out.println(atomicInteger.decrementAndGet()); --121 先自减再获取减1后的值
            System.out.println(atomicInteger.get()); --121
    

    3、使用AtomicInteger,即使不用同步块synchronized,最后的结果也是100,可用看出AtomicInteger的作用,用原子方式更新的int值。主要用于在高并发环境下的高效程序处理。使用非阻塞算法来实现并发控制。

    public class Counter {
    
        public static AtomicInteger count = new AtomicInteger(0);
    
        public static void inc(){
            try{
                Thread.sleep(1); //延迟1毫秒
    
            }catch (InterruptedException e){ //catch住中断异常,防止程序中断
                e.printStackTrace();
    
            }
            count.getAndIncrement();//count值自加1
        }
    
    
        public static void main(String[] args) throws InterruptedException {
    
    
            final CountDownLatch latch = new CountDownLatch(100);
    
            for(int i=0;i<100;i++){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Counter.inc();
                        latch.countDown();
                    }
                }).start();
            }
            latch.await();
    
            System.out.println("运行结果:"+Counter.count);
    
    
        }
    }
    

    运行结果: 100

    4、使用普通Integer

    public class Counter {
    
        public volatile  static int count = 0;
    
        public static void inc(){
            try{
                Thread.sleep(1); //延迟1毫秒
    
            }catch (InterruptedException e){ //catch住中断异常,防止程序中断
                e.printStackTrace();
    
            }
            count++;//count值自加1
        }
    
    
        public static void main(String[] args) throws InterruptedException {
    
    
            final CountDownLatch latch = new CountDownLatch(100);
    
            for(int i=0;i<100;i++){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Counter.inc();
                        latch.countDown();
                    }
                }).start();
            }
            latch.await();
    
            System.out.println("运行结果:"+Counter.count);
       }
    }
    运行结果:98
    

    5、如果在inc方法前面加个synchronized也能是线程安全的;

    它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

    import java.util.concurrent.CountDownLatch;
    
    /**
     * created by guanguan  on 2017/10/23
     **/
    public class Counter {
    
         public volatile static  Integer count = 0;
    
        public synchronized static void inc(){
            try{
                Thread.sleep(1); //延迟1毫秒
    
            }catch (InterruptedException e){ //catch住中断异常,防止程序中断
                e.printStackTrace();
    
            }
              count++;//count值自加1
        }
    
    
        public static void main(String[] args) throws InterruptedException {
    
    
            final CountDownLatch latch = new CountDownLatch(100);
    
            for(int i=0;i<100;i++){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Counter.inc();
                        latch.countDown();
                    }
                }).start();
            }
            latch.await();
    
            System.out.println("运行结果:"+Counter.count);
    
    
        }
    }
    
    运行结果:100
    

    synchronized的使用说明:

    一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

    二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

    三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

    四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

    五、以上规则对其它对象锁同样适用.

    6、从上面的例子中我们可以看出:使用AtomicInteger是非常的安全的.而且因为AtomicInteger由硬件提供原子操作指令实现的。在非激烈竞争的情况下,开销更小,速度更快。

    java的关键域有3个

    // setup to use Unsafe.compareAndSwapInt for updates  
    private static final Unsafe unsafe = Unsafe.getUnsafe();  
    private static final long valueOffset;  
    private volatile int value; 
    

    这里, unsafe是java提供的获得对对象内存地址访问的类,注释已经清楚的写出了,它的作用就是在更新操作时提供“比较并替换”的作用。实际上就是AtomicInteger中的一个工具。

    valueOffset是用来记录value本身在内存的便宜地址的,这个记录,也主要是为了在更新操作在内存中找到value的位置,方便比较。

    注意:value是用来存储整数的时间变量,这里被声明为volatile,就是为了保证在更新操作时,当前线程可以拿到value最新的值(并发环境下,value可能已经被其他线程更新了)。

    这里,我们以自增的代码为例,可以看到这个并发控制的核心算法:

    源码

     public final int updateAndGet(IntUnaryOperator updateFunction) {
            int prev, next;
            do {
                prev = get();
                next = updateFunction.applyAsInt(prev);
            } while (!compareAndSet(prev, next));
            return next;
        }
    

    相关文章

      网友评论

        本文标题:Java AtomicInteger的用法

        本文链接:https://www.haomeiwen.com/subject/vaapkctx.html