Java AtomicInteger类使用方法实例讲解

作者:King-D 时间:2023-01-18 16:22:49 

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;
 }

来源:https://www.cnblogs.com/qingmuchuanqi48/p/13125268.html

标签:Java,AtomicInteger,类
0
投稿

猜你喜欢

  • IDEA启动tomcat控制台中文乱码问题的解决方法(100%有效)

    2021-06-25 10:45:23
  • Springboot自带定时任务实现动态配置Cron参数方式

    2023-11-10 10:21:31
  • 如何优雅的处理Spring Boot异常信息详解

    2023-11-29 09:50:02
  • flutter实现扫码枪获取数据源禁止系统键盘弹窗示例详解

    2023-07-23 01:52:41
  • Spring Boot利用@Async如何实现异步调用:自定义线程池

    2021-11-09 17:32:11
  • 详解java接口基础知识附思维导图

    2023-11-09 10:07:28
  • Java中间消息件ActiveMQ使用实例

    2021-10-10 14:24:21
  • Java线程池submit阻塞获取结果的实现原理详解

    2021-08-29 03:55:45
  • Java开发环境配置方法

    2022-05-25 02:02:29
  • Java冒泡排序的定义与实例代码

    2022-03-29 12:32:31
  • 基于Java实现双向链表

    2022-11-17 11:39:16
  • JAVA常用API总结与说明

    2023-05-19 08:17:17
  • Java经典面试题最全汇总208道(二)

    2023-11-09 08:13:39
  • Spring Boot示例分析讲解自动化装配机制核心注解

    2022-07-26 15:56:14
  • 解决nacos升级spring cloud 2020.0无法使用bootstrap.yml的问题

    2021-12-02 19:44:29
  • Springboot Vue实现单点登陆功能示例详解

    2023-11-05 00:29:11
  • Java的数据类型和参数传递(详解)

    2022-12-30 18:52:25
  • Java操作hdfs文件系统过程

    2023-12-13 23:42:32
  • Java实战之基于swing的QQ邮件收发功能实现

    2023-11-15 01:34:26
  • SpringBoot 整合jdbc和mybatis的方法

    2023-08-10 12:51:09
  • asp之家 软件编程 m.aspxhome.com