线程安全性-原子性

线程安全性-原子性

1.Atomic包

Atomic包简单使用,能有效的确保数据的原子性,此处用AtomicInteger来进行计数(其他的都差不多)

//默认计数器的值为0
public static AtomicLong count = new AtomicLong(0);
//同时并发执行的线程数
public static int threadTotal = 200;
//请求总数
public static int  clientTotal = 5000;

public static void main(String[] args) throws InterruptedException {
        //创建线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        //计数信号量 每个acquire方法阻塞,直到有一个许可证可以获得然后拿走一个许可证;每个release方法增加一个许可证,这可能会释放一个阻塞的acquire方法。
        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();
                    //计数器减一
                    countDownLatch.countDown();
                } catch (Exception e) {
                    log.error("exception",e);
                }
            });
        }
        //线程阻塞,等待计数器减为0释放
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}",count.get());
    }

 private static void add(){
        //相当于++count
        count.incrementAndGet();
        //相当于count++
        //count.getAndIncrement();
 }

执行完结果为5000,没有出现线程问题,接下看,我们来分析一下atomic的incrementAndGet()方法是如何保证线程的原子性的。

/**
 * Atomically increments by one the current value.
 *
 * @return the updated value
 */
 public final long incrementAndGet() {
      return unsafe.getAndAddInt(this, valueOffset, 1L) + 1L;
 }

/**
 * var1:传入的对象 var2:当前的值 
 * var4:需要增加的值 var6:当前内存中存在的值
 */
public final long getAndAddLong(Object var1, long var2, long var4) {
        long var6;
        do {
            //在内存中取出当前的值
            var6 = this.getIntVolatile(var1, var2);
            //this.compareAndSwapLong(var1, var2, var6, var6 + var4) 将传入的var2与取出的var6进行对比,如果值相同,说明其他线程没有进行修改,则进行修改操作并退出循环,如果值不同,继续取出数据进行比较
        } while(!this.compareAndSwapInt(var1, var2, var6, var6 + var4));

        return var6;
    }

总结:

在并发较低的情况下使用atmoic可以提高效率,一旦并发高了以后,执行unsafe.getAndAddInt()方法时,可能会循环多次取出值来进行判断,导致性能降低。并发高时,可以使用LongAdder类来进行处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值