java并发测试:线程安全与线程不安全,使用AtomicLong和LongAdder演示代码保证线程安全

1.使用基础变量int(线程不安全)

package com.zr.concurrency.test;

import com.zr.concurrency.annotation.ThreadNotSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @description: 并发测试,线程不安全
 * @author: liangrui
 * @create: 2019-12-29 12:31
 **/
@Slf4j
@ThreadNotSafe
public class ConcurrencyTest {
    //请求总数
    private static int clientTotal=5000;
    //同时并发执行的线程数
    private static int threadTotal=200;
    //计数
    private static int count=0;

    /**
     * 每个线程执行一次
     */
    private static void add(){
        count++;
    }

    public static void main(String[] args) throws InterruptedException {
        //创建线程池
        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 (InterruptedException e) {
                            e.printStackTrace();
                        }
                        // 当前线程执行完才释放
                        countDownLatch.countDown();
                    }
            );
        }
        //所有线程执行完才释放
        countDownLatch.await();
        //关闭线程池
        executorService.shutdown();
        //输出count值
        log.info("count:{}",count);
    }
}

输出结果:5000才是应该输出的值

18:28:31.377 [main] INFO com.zr.concurrency.test.ConcurrencyTest - count:4957

2.使用AtomicLong和LongAdder的代码(线程安全)

AtomicLong:
  使用死循环不断地compareAndSwap到特定的值,从而达到更新数据的目的
  缺点:唯一会制约AtomicLong高效的原因是高并发,高并发意味着CAS的失败几率更高,重试次数更多,越多线程重试,CAS失败几率又越高,变成恶性循环,AtomicLong效率降低
  
LongAdder:
  高并发时:将对单一变量的CAS操作分散为对数组cells中多个元素的CAS操作,取值时进行求和;
  并发较低时:仅对base变量进行CAS操作,与AtomicLong类原理相同,不得不说这种分布式的设计还是很巧妙的。
  缺点: 在统计的时候,如果有并发更新,可能会导致统计数据有些误差

package com.zr.concurrency.test;

import com.zr.concurrency.annotation.ThreadNotSafe;
import com.zr.concurrency.annotation.ThreadSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * @description: 并发测试,使用AtomicLong或者LongAdder,这样是线程安全的
 * AtomicLong:使用死循环不断地compareAndSwap到特定的值,从而达到更新数据的目的
 *      唯一会制约AtomicLong高效的原因是高并发,高并发意味着CAS的失败几率更高,
 *      重试次数更多,越多线程重试,CAS失败几率又越高,变成恶性循环,AtomicLong效率降低
 * LongAdder:
 *      高并发时:将对单一变量的CAS操作分散为对数组cells中多个元素的CAS操作,取值时进行求和;
 *      并发较低时:仅对base变量进行CAS操作,与AtomicLong类原理相同。
 *      不得不说这种分布式的设计还是很巧妙的。
 *      缺点: 在统计的时候,如果有并发更新,可能会导致统计数据有些误差
 * @author: liangrui
 * @create: 2019-12-29 12:31
 **/
@Slf4j
@ThreadSafe
public class ConcurrencyTest2 {
    //请求总数
    private static int clientTotal=5000;
    //同时并发执行的线程数
    private static int threadTotal=200;
    //计数从0开始
    private static AtomicLong count=new AtomicLong(0);
    //也可以使用LongAdder
    private static LongAdder count2=new LongAdder();
    /**
     * 每个线程执行一次
     */
    private static void add(){
        count.incrementAndGet();
        count2.increment();
    }

    public static void main(String[] args) throws InterruptedException {
        //创建线程池
        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 (InterruptedException e) {
                            e.printStackTrace();
                        }
                        // 当前线程执行完才释放
                        countDownLatch.countDown();
                    }
            );
        }
        //所有线程执行完才释放
        countDownLatch.await();
        //关闭线程池
        executorService.shutdown();
        //输出count值
        log.info("count:{}",count);
        log.info("count2:{}",count2);
    }
}

输出结果:都为5000,线程安全

18:30:12.479 [main] INFO com.zr.concurrency.test.ConcurrencyTest2 - count:5000
18:30:12.485 [main] INFO com.zr.concurrency.test.ConcurrencyTest2 - count2:5000

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值