记录自己基于SpringBoot对多线程并发进行学习
一.准备工作
配置SpringBoot,在GIT上创建项目,将创建导入本地
测试Spring是否启动成功,测试是否返回test
写了4个annotations,用来表示安全和不安全,推荐和不推荐写法
其中使用了lombok
线程安全性
定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式,或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为.那么就称这个类时线程安全的
体现方面: 原子性:提供了互斥访问,同一时刻只能有一个线程来对它进行操作
可见性:一个线程对主内存的修改可以及时的被其他线程观察到
有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排的存在,该观察结果一般杂乱无序
原子性-AtomicInteger 使用example1和example2说明 注意Semaphore的使用
//example2
@ThreadSafe
@Slf4j
public class CoutntExample2 {
//请求总数
public static int clientTotal=15000;
//同时并发执行的线程数
public static int threadTotal=20;
public static AtomicInteger count=new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
ThreadFactory threadFactory = new ThreadFactoryBuilder().
setNameFormat("Example1").build();
ThreadPoolExecutor executorService = new ThreadPoolExecutor(
10, 50, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingDeque(1024), threadFactory,
new ThreadPoolExecutor.AbortPolicy());
Semaphore semaphore = new Semaphore(threadTotal);
CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i {
try {
semaphore.acquire();
add();
semaphore.release();
}catch (Exception e){
log.error("exception",e);
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
log.info("count:{}",count.get());
}
public static void add(){
count.incrementAndGet();
}
}
其中查看 incrementAndGet()源码
再看getAndAddInt()
其中compareAndSwapInt为一个native方法
三个参数分别为,var变量,取出当前var变量的valueOffset,取出的值var5,若相等的话,var5的值=var5+var4
1.你的线程池ThreadPoolExecutor 显示的shutdown()之后,再向线程池提交任务的时候。如果你配置的拒绝策略是AbortPolicy的话,这个异常就会抛出来。
2.队列满了,而且池中的线程数也达到了最大线程数,所以新添加的任务被拒绝了。
这种情况,可以调整一下线程池的策略
-AtomicLong和LongAdder包
对应优点:LongAdder在AtomicLong的基础上,将单点的更新压力分散到各个节点上,在低并发的时候,通过对base的直接更新,保证性能和AtomicLong基本一致;在高并发的时候通过分散提高性能.
缺点:统计的时候,若有并发更新,可能会导致统计的数据有些误差(cell累加)
实际使用中,在处理高并发的数据时可以优先使用LongAdder而不是AtomicLong,在线程竞争很低的时候推荐使用AtomicLong.序列号生成需要准确的数值,应该使用AtomicLong
-AtomicReference和AtomicIntergerFieldUpdeter的使用
-AtomicStampReference: CAS的ABA问题解决(版本号加1)
-AtomicLongArray: 维护的一个数组,额外多一个索引值去更新
-AtomicBoolean: 若希望某段代码执行一次,使用此