首页
关于
友链
Search
1
wlop 4K 壁纸 4k8k 动态 壁纸
1,470 阅读
2
Nacos持久化MySQL问题-解决方案
932 阅读
3
Docker搭建Typecho博客
752 阅读
4
滑动时间窗口算法
728 阅读
5
Nginx反向代理微服务配置
699 阅读
生活
解决方案
JAVA基础
JVM
多线程
开源框架
数据库
前端
分布式
框架整合
中间件
容器部署
设计模式
数据结构与算法
安全
开发工具
百度网盘
天翼网盘
阿里网盘
登录
Search
标签搜索
java
javase
docker
java8
springboot
thread
spring
分布式
mysql
锁
linux
redis
源码
typecho
centos
git
map
RabbitMQ
lambda
stream
少年
累计撰写
189
篇文章
累计收到
24
条评论
首页
栏目
生活
解决方案
JAVA基础
JVM
多线程
开源框架
数据库
前端
分布式
框架整合
中间件
容器部署
设计模式
数据结构与算法
安全
开发工具
百度网盘
天翼网盘
阿里网盘
页面
关于
友链
搜索到
2
篇与
的结果
2022-04-24
线程安全-并发容器J.U.C
线程安全-并发容器J.U.CArrayList -> CopyOnWriteArrayListHashSet、TreeSet -> CopyOnWriteArraySet 、ConcurrentSkipListSetHashMap、TreeMap -> ConcurrentHashMap 、ConcurrentSkipListMapCopyOnWriteArrayList适合读多写少的场景。读的时候再原数组读不需要加锁,写的时候会copy一份会单独加锁。代码示例:package com.yanxizhu.demo.concurrency.concurrent; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; /** * @description: 线程安全容器:CopyOnWriteArrayList * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:52 * @version: 1.0 */ @Slf4j @ThreadSafety public class DemoCopyOnWriteArrayList { // 请求总数 public static int clientTotal = 5000; // 同时并发执行的线程数 public static int threadTotal = 200; private static List<Integer> list = new CopyOnWriteArrayList<>(); 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++) { final int count = i; executorService.execute(() -> { try { semaphore.acquire(); update(count); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("size:{}", list.size()); } private static void update(int i) { list.add(i); } }输出结果:5000CopyOnWriteArraySet线程安全,代码示例package com.yanxizhu.demo.concurrency.concurrent; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.Set; import java.util.concurrent.*; /** * @description: 线程安全容器:CopyOnWriteArraySet * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:52 * @version: 1.0 */ @Slf4j @ThreadSafety public class DemoCopyOnWriteArraySet { // 请求总数 public static int clientTotal = 5000; // 同时并发执行的线程数 public static int threadTotal = 200; private static Set<Integer> set = new CopyOnWriteArraySet<>(); 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++) { final int count = i; executorService.execute(() -> { try { semaphore.acquire(); update(count); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("set size:{}", set.size()); } private static void update(int i) { set.add(i); } }输出结果:set size:5000,线程安全ConcurrentSkipListSet线程安全,代码示例package com.yanxizhu.demo.concurrency.concurrent; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.List; import java.util.Set; import java.util.concurrent.*; /** * @description: 线程安全容器:ConcurrentSkipListSet * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:52 * @version: 1.0 */ @Slf4j @ThreadSafety public class DemoConcurrentSkipListSet { // 请求总数 public static int clientTotal = 5000; // 同时并发执行的线程数 public static int threadTotal = 200; private static Set<Integer> set = new ConcurrentSkipListSet<>(); 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++) { final int count = i; executorService.execute(() -> { try { semaphore.acquire(); update(count); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("set size:{}", set.size()); } private static void update(int i) { set.add(i); } }输出结果:5000,线程安全。注意:单纯的add、remove是线程安全的,contains等是不安全的。ConcurrentHashMap线程安全,适合并发量大场景package com.yanxizhu.demo.concurrency.concurrent; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.HashMap; import java.util.Map; import java.util.concurrent.*; /** * @description: 线程安全容器:ConcurrentHashMap适合高并发场景 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:52 * @version: 1.0 */ @Slf4j @UnThreadSafety public class DemoConcurrentHashMap { private static Map<Integer, Integer> map = new ConcurrentHashMap<>(); //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(concurrencyTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal); for (int i = 0; i < clientsTotal; i++) { final int count = i; executorService.execute(()->{ try { semaphore.acquire(); update(count); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("map size:{}", map.size()); } /** * 通过线程安全对象dateTimeFormatter处理 */ private static void update(int count){ map.put(count, count); } }输出结果:5000,线程安全ConcurrentSkipListMap线程安全,随着并发量增加性能表现越强,大并发下使用ConcurrentHashMap,并发一直增加推荐使用ConcurrentSkipListMap。package com.yanxizhu.demo.concurrency.concurrent; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.Map; import java.util.concurrent.*; /** * @description: 线程安全容器:ConcurrentSkipListMap,随着并发的增加性能表现的越好 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:52 * @version: 1.0 */ @Slf4j @UnThreadSafety public class DemoConcurrentHashMap1 { private static Map<Integer, Integer> map = new ConcurrentSkipListMap<>(); //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(concurrencyTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal); for (int i = 0; i < clientsTotal; i++) { final int count = i; executorService.execute(()->{ try { semaphore.acquire(); update(count); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("map size:{}", map.size()); } /** * 通过线程安全对象dateTimeFormatter处理 */ private static void update(int count){ map.put(count, count); } }输出结果:5000,线程安全。注意:ConcurrentHashMap与ConcurrentSkipListMap的使用场景。小总结:线程限制:一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改共享只读:一个共享只读的对象,在没有额外同步的情况下,可以被多个线程并发访问,但是任何线程都不能修改它。线程安全对象:一个线程安全的对象或者容器,在内部通过同步机制来保证线程安全,所以其他线程无需额外的同步就可以通过公共接口随意访问它被守护对象:被守护对象只能通过获取特定的锁来访问
2022年04月24日
186 阅读
0 评论
3 点赞
2022-04-24
线程不安全的类与写法
线程不安全的类与写法线程不安全的类:类的对象可以同时被多个线程访问,比如抛出异常,逻辑错误。下面介绍一些常见的类。StringBuilderStringBuilder线程不安全的类代码示例package com.yanxizhu.demo.concurrency.threadUnSafetyClass; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; 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: 线程不安全的类:StringBuilder * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:01 * @version: 1.0 */ @Slf4j @UnThreadSafety public class DemoStringBuilder { //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; //累加总和 private static StringBuilder stringBuilder = new StringBuilder(); public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(concurrencyTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal); for (int i = 0; i < clientsTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); update(); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("字符长度Length=【{}】",stringBuilder.length()); } /** * 累加 */ private static void update(){ stringBuilder.append(1); } }每次输出字符长度不一样,也不等于5000StringBuffer线程安全的类代码示例package com.yanxizhu.demo.concurrency.threadUnSafetyClass; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; 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: 线程安全的类:StringBuffer * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:06 * @version: 1.0 */ @Slf4j @ThreadSafety public class DemoStringBuffer { //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; //累加总和 private static StringBuffer stringBuffer = new StringBuffer(); public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(concurrencyTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal); for (int i = 0; i < clientsTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); update(); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("字符长度Length=【{}】", stringBuffer.length()); } /** * 累加 */ private static void update(){ stringBuffer.append(1); } }输出结果:每次都是长度为5000.StringBuffer为什么线程安全,看源码 @Override @HotSpotIntrinsicCandidate public synchronized StringBuffer append(int i) { toStringCache = null; super.append(i); return this; }因为StringBuffer所有的方法操作都加了synchronized。区别StringBuffer由于加了synchronized,性能上有损耗,没有StringBuilder性能高,在线程封闭中,堆栈封闭时,一般处理字符串局部变量时用StringBuilfer就行了。SimpleDateFormat线程不安全的类代码示例package com.yanxizhu.demo.concurrency.threadUnSafetyClass; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; import lombok.extern.slf4j.Slf4j; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * @description: 线程不安全类: SimpleDateFormat * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:18 * @version: 1.0 */ @Slf4j @UnThreadSafety public class DemoSimpleDateFormat { private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyyMMMdd"); //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(concurrencyTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal); for (int i = 0; i < clientsTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); update(); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); } /** * 累加 */ private static void update(){ try { simpleDateFormat.parse("20220424"); } catch (ParseException e) { log.error(e.getMessage()); } } }输出结果: at java.base/java.lang.Double.parseDouble(Double.java:543) at java.base/java.text.DigitList.getDouble(DigitList.java:169) at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2126) at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933) at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541) at java.base/java.text.DateFormat.parse(DateFormat.java:393) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) Exception in thread "pool-1-thread-824" java.lang.NumberFormatException: For input string: "E.0220E0" at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054) at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110) at java.base/java.lang.Double.parseDouble(Double.java:543) at java.base/java.text.DigitList.getDouble(DigitList.java:169) at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2126) at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933) at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541) at java.base/java.text.DateFormat.parse(DateFormat.java:393) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) Exception in thread "pool-1-thread-717" java.lang.NumberFormatException: multiple points at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1890) at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110) at java.base/java.lang.Double.parseDouble(Double.java:543) at java.base/java.text.DigitList.getDouble(DigitList.java:169) at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2126) at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933) at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541) at java.base/java.text.DateFormat.parse(DateFormat.java:393) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) Exception in thread "pool-1-thread-671" java.lang.NumberFormatException: For input string: "" at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.base/java.lang.Long.parseLong(Long.java:702) at java.base/java.lang.Long.parseLong(Long.java:817) at java.base/java.text.DigitList.getLong(DigitList.java:195) at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2121) at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933) at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541) at java.base/java.text.DateFormat.parse(DateFormat.java:393) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) Exception in thread "pool-1-thread-805" java.lang.NumberFormatException: multiple points at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1914) at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110) at java.base/java.lang.Double.parseDouble(Double.java:543) at java.base/java.text.DigitList.getDouble(DigitList.java:169) at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2126) at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933) at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541) at java.base/java.text.DateFormat.parse(DateFormat.java:393) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) Exception in thread "pool-1-thread-736" java.lang.NumberFormatException: For input string: ".20220424" at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.base/java.lang.Long.parseLong(Long.java:678) at java.base/java.lang.Long.parseLong(Long.java:817) at java.base/java.text.DigitList.getLong(DigitList.java:195) at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2121) at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933) at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541) at java.base/java.text.DateFormat.parse(DateFormat.java:393) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) Exception in thread "pool-1-thread-740" java.lang.NumberFormatException: multiple points at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1914) at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110) at java.base/java.lang.Double.parseDouble(Double.java:543) at java.base/java.text.DigitList.getDouble(DigitList.java:169) at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2126) at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933) at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541) at java.base/java.text.DateFormat.parse(DateFormat.java:393) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) Exception in thread "pool-1-thread-695" java.lang.NumberFormatException: For input string: "E.0220" at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054) at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110) at java.base/java.lang.Double.parseDouble(Double.java:543) at java.base/java.text.DigitList.getDouble(DigitList.java:169) at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2126) at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933) at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541) at java.base/java.text.DateFormat.parse(DateFormat.java:393) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) Exception in thread "pool-1-thread-888" java.lang.NumberFormatException: For input string: "202204242022042420220424" at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.base/java.lang.Long.parseLong(Long.java:692) at java.base/java.lang.Long.parseLong(Long.java:817) at java.base/java.text.DigitList.getLong(DigitList.java:195) at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2121) at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933) at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541) at java.base/java.text.DateFormat.parse(DateFormat.java:393) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57) at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834)虽然SimpleDateFormat是线程不安全的类,但是可以通过线程封闭中,堆栈封闭(栈封闭)方法,将SimpleDateFormat定义到局部变量中,每次是一个新对象,这样来保证线程安全。package com.yanxizhu.demo.concurrency.threadUnSafetyClass; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; import lombok.extern.slf4j.Slf4j; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * @description: 线程不安全类: SimpleDateFormat,通过堆栈封闭,实现线程安全。 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:18 * @version: 1.0 */ @Slf4j @ThreadSafety public class DemoSimpleDateFormatOk { //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(concurrencyTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal); for (int i = 0; i < clientsTotal; i++) { executorService.execute(()->{ try { semaphore.acquire(); update(); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); } /** * 通过线程封闭,将SimpleDateFormat定义在方法内,每次都是一个新的对象,来保证线程安全 */ private static void update(){ try { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyyMMMdd"); simpleDateFormat.parse("20220424"); } catch (ParseException e) { log.error(e.getMessage()); } } }输出结果:输出5000条,一样的。09:27:17.633 [pool-1-thread-461] ERROR com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormatOk - Unparseable date: "20220424" 09:27:17.633 [pool-1-thread-460] ERROR com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormatOk - Unparseable date: "20220424" 09:27:17.634 [pool-1-thread-452] ERROR com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormatOk - Unparseable date: "20220424" 09:27:17.634 [pool-1-thread-445] ERROR com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormatOk - Unparseable date: "20220424" 09:27:17.634 [pool-1-thread-453] ERROR com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormatOk - Unparseable date: "20220424" 。。。。。joda.time第三方包中DateTimeFormatter代码示例package com.yanxizhu.demo.concurrency.threadUnSafetyClass; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import lombok.extern.slf4j.Slf4j; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import java.util.Date; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * @description: 线程安全的类:Joda-time包里面的DateTimeFormatter需要单独导入 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:31 * @version: 1.0 */ @Slf4j @ThreadSafety public class DemoJodaTime { private static DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyyMMdd"); //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(clientsTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(concurrencyTotal); for (int i = 0; i < clientsTotal; i++) { final int count = i; executorService.execute(()->{ try { semaphore.acquire(); update(count); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); } /** * 通过线程安全对象dateTimeFormatter处理 */ private static void update(int count){ Date date = DateTime.parse("20220424", dateTimeFormatter).toDate(); log.info("{},{}", count, date); } }输出结果:有5000条,线程安全的09:45:06.164 [pool-1-thread-1947] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 1946,Sun Apr 24 00:00:00 CST 2022 09:45:06.154 [pool-1-thread-491] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 490,Sun Apr 24 00:00:00 CST 2022 09:45:06.184 [pool-1-thread-2943] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 2942,Sun Apr 24 00:00:00 CST 2022 09:45:06.169 [pool-1-thread-1911] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 1910,Sun Apr 24 00:00:00 CST 2022 09:45:06.169 [pool-1-thread-616] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 615,Sun Apr 24 00:00:00 CST 2022 09:45:06.168 [pool-1-thread-2551] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 2550,Sun Apr 24 00:00:00 CST 2022 09:45:06.144 [pool-1-thread-1415] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 1414,Sun Apr 24 00:00:00 CST 2022 09:45:06.154 [pool-1-thread-4611] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 4610,Sun Apr 24 00:00:00 CST 2022 09:45:06.169 [pool-1-thread-4760] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 4759,Sun Apr 24 00:00:00 CST 2022 09:45:06.167 [pool-1-thread-2388] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 2387,Sun Apr 24 00:00:00 CST 2022 09:45:06.184 [pool-1-thread-3990] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 3989,Sun Apr 24 00:00:00 CST 2022 。。。。。ArrayList线程不安全的代码示例package com.yanxizhu.demo.concurrency.threadUnSafetyClass; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; import lombok.extern.slf4j.Slf4j; import org.checkerframework.checker.units.qual.A; import org.joda.time.DateTime; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * @description: 线程不安全类:ArrayList * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:52 * @version: 1.0 */ @Slf4j @UnThreadSafety public class DemoArrayList { private static List<Integer> list = new ArrayList<>(); //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(concurrencyTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal); for (int i = 0; i < clientsTotal; i++) { final int count = i; executorService.execute(()->{ try { semaphore.acquire(); update(count); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("list size:{}", list.size()); } /** * 通过线程安全对象dateTimeFormatter处理 */ private static void update(int count){ list.add(count); } }输出结果:每次输出ist长度不同,线程不安全的。HashSet线程不安全类代码示例package com.yanxizhu.demo.concurrency.threadUnSafetyClass; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * @description: 线程不安全类:HashSet * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:52 * @version: 1.0 */ @Slf4j @UnThreadSafety public class DemoHashSet { private static Set<Integer> set = new HashSet<>(); //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(concurrencyTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal); for (int i = 0; i < clientsTotal; i++) { final int count = i; executorService.execute(()->{ try { semaphore.acquire(); update(count); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("set size:{}", set.size()); } /** * 通过线程安全对象dateTimeFormatter处理 */ private static void update(int count){ set.add(count); } }输出结果:每次长度不同,不是5000,线程不安全。HashMap线程不安全的代码示例package com.yanxizhu.demo.concurrency.threadUnSafetyClass; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * @description: 线程不安全类:HashMap * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/24 9:52 * @version: 1.0 */ @Slf4j @UnThreadSafety public class DemoHashMap { private static Map<Integer, Integer> map = new HashMap(); //用户数量 private static final int clientsTotal = 5000; //并发数量 private static final int concurrencyTotal = 200; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //信号量 final Semaphore semaphore = new Semaphore(concurrencyTotal); //闭锁 final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal); for (int i = 0; i < clientsTotal; i++) { final int count = i; executorService.execute(()->{ try { semaphore.acquire(); update(count); semaphore.release(); } catch (InterruptedException e) { log.error("出现错误:【{}】", e.getMessage()); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("map size:{}", map.size()); } /** * 通过线程安全对象dateTimeFormatter处理 */ private static void update(int count){ map.put(count, count); } }输出结果: 长度不是5000,每次长度不一样,线程不安全。总结:线程安全类对应的不只一个。后面专门说明。注意:先检查再执行这种类是线程不安全的,因为被分成2步了,if (condition(a)) { handle(1);}
2022年04月24日
230 阅读
0 评论
2 点赞