线程安全性-原子性-Atomic包-1

本文详细介绍了线程安全的概念及其三个核心属性:原子性、可见性和有序性。通过具体的Java代码示例,深入剖析了Atomic包下各类原子类如AtomicInteger、AtomicLong等的工作原理,展示了它们如何确保多线程环境下的数据一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.什么是线程安全性:

定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。

二.线程安全性表现在三方面:

  1. 原子性:提供互斥访问,在同一时刻只能有一个线程对他访问
  2. 可见性:一个线程对内存的修改可以及时的被其他线程观察到
  3. 有序性:一个线程观察其他线程中的指令顺序,由于指令重排序的存在,观察结果一般杂乱无序

三:原子性–Atomic包

Atomic包都是通过CAS理论完成线程的原子性
AtomicInteger类 ,会出现循环

public class AtomicExple1 {
    // 请求总数
    public static int clientTotal = 5000;

    // 同时并发执行的线程数
    public static int threadTotal = 200;

    //原子特性atomic
    public static AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count.get());
    }

    private static void add() {
        //这是表现线程安全,及原子性
        count.incrementAndGet();//先增后取值
        // count.getAndIncrement();
    }
}

备注:为什么表现出原子性
在这里插入图片描述
在这里插入图片描述

源码分析:

//var1是count的对象,var2是当前对象在内存的偏移量,var4 就是1(要加上的值)
	public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
        	//获取对象内存地址偏移量上的数值var5
            var5 = this.getIntVolatile(var1, var2);
            //如果现在还是var5,设置为 var5 + var4,否则返回false,继续循环再次重试.
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

四.AtomicLong,LongAdder这两个类,线程安全

大量线程并发更新一个原子类的时候,天然的一个问题就是自旋,分段迁移,某一个线程如果对一个Cell更新的时候,发现说出现了很难更新他的值,出现了多次自旋的一个问题,如果他CAS失败了,自动迁移段,他会去尝试更新别的Cell的值,这样的话就可以让一个线程不会盲目的等待一个cell的值.
LongAdder原理图:
在这里插入图片描述

五.AtomicReference,AtomicReferenceFieldUpdater类:

  • AtomicReference
 private static AtomicReference<Integer> count = new AtomicReference<>(0);

  public static  void main(String[] args){
    count.compareAndSet(0, 2);//count等于0时候复制给2
    count.compareAndSet(0, 1);
    count.compareAndSet(1, 3);
    count.compareAndSet(2, 4);
    count.compareAndSet(3, 5);
    log.info("count {}", count.get());//最后输出为4
  }
  • AtomicReferenceFieldUpdater
public class CountExample5 {
  /**
   * param:是要更新的类型
   */
  private static AtomicIntegerFieldUpdater<CountExample5> updater =
          AtomicIntegerFieldUpdater.newUpdater(CountExample5.class, "count");//要更新的字段

  @Getter
  private  volatile int count = 100;//要更新的字段,必须有volatile修饰
  //更新的类型
  private static CountExample5 countExample5 = new CountExample5();

  public static  void main(String[] args){
    if(updater.compareAndSet(countExample5, 100, 120)){
      log.info("update success 1 {}", countExample5.getCount());//120;
    }
    if(updater.compareAndSet(countExample5, 100, 120)){
      log.info("update success 2 {}", countExample5.getCount());
    }else {
      log.error("update fail {}", countExample5.getCount());//120
    }
  }
}

六:AtomicStampReference:解决了CAS理论的ABA问题;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值