CountDownLatch等待多线程并发的工具类

本文通过一个CountDownLatch的例子展示了在多线程环境下,不安全的自增运算可能导致结果错误。由于自增操作不是原子性的,当多个线程同时访问时,可能会丢失更新,造成最终结果与预期不符。分析了自增操作的非原子性,并讨论了线程安全问题的重要性。
摘要由CSDN通过智能技术生成
/**
 * CountDownLatch(倒数闩)是一个非常实用的等待多线程并发的工具类。
 * 10个线程并行运行,对一个共享数据进行自增运算,每个线程自增运算1000次,具体
 * @author ADMIN
 *
 */
public class CountDownLatchTest {
   final static int  max_tread =10;//10个线程并行运行
   final static int max_run =1000;//每个线程自增运算1000次
   //测试不安全的累加器
   public static void main(String[] args) throws InterruptedException {
      //倒数闩 需要倒数10次
      CountDownLatch latch =new CountDownLatch(max_tread);
      NotSafePlus count=new NotSafePlus();
      Runnable runn=()->{
         System.out.println(Thread.currentThread().getName());
         for(int i=0;i<max_run;i++) {
            count.selfPlus();
         }
         latch.countDown();//倒数闩减少一次
      };
      for(int i=0;i<max_tread;i++) {
         new Thread(runn).start();
      }
      latch.await();//等待倒数闩的次数减少到0,所有线程执行完毕
      System.out.println("理论结果为:"+max_tread *max_run);
      System.out.println("实际结果为:"+count.getAmount());
      System.out.println("差距为:"+(max_tread *max_run -count.getAmount()));
      
      
   }
}
class NotSafePlus{
   private Integer amount=0;
   //自增
   public void selfPlus() {
      amount++;
   }
   public Integer getAmount() {
      return amount;
   }
   public void setAmount(Integer amount) {
      this.amount = amount;
   }
   
}

为什么自增运算符不是线程安全的呢?实际上,一个自增运算符是 一个复合操作,至少包括三个JVM指令:“内存取值”“寄存器增加 1”和“存值到内存”。这三个指令在JVM内部是独立进行的,中间完全可 能会出现多个线程并发进行。

比如在amount=100时,假设有三个线程同一时间读取amount值,读 到的都是100,增加1后结果为101,三个线程都将结果存入amount的内 存,amount的结果是101,而不是103。

“内存取值”“寄存器增加1”和“存值到内存”这三个JVM指令本身是不 可再分的,它们都具备原子性,是线程安全的,也叫原子操作。但是, 两个或者两个以上的原子操作合在一起进行操作就不再具备原子性了。 比如先读后写,就有可能在读之后,其实这个变量被修改了,出现读和 写数据不一致的情况

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值