线程不安全的类与写法
线程不安全的类:类的对象可以同时被多个线程访问,比如抛出异常,逻辑错误。下面介绍一些常见的类。
StringBuilder
StringBuilder线程不安全的类
代码示例
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);
}
}
每次输出字符长度不一样,也不等于5000
StringBuffer
线程安全的类
代码示例
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);}
评论 (0)