线程不安全类与写法
StringBuilder->StringBuffer
StringBuilder实例
//请求总数
private static int clientTotal=5000;
//同时并发请求的线程数
private static int threadTotal=200;
public static StringBuilder builder=new StringBuilder();
public static LongAdder longAdder=new LongAdder();
// public static int count=0;
public static void main(String[] args) throws Exception {
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(new Runnable() {
public void run() {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
update();
semaphore.release();
countDownLatch.countDown();
}
});
}
countDownLatch.await();
executorService.shutdown();
// System.out.println("count:"+count);
System.out.println("length:"+builder.length());
}
private static void update() {
builder.append("1");
}
注:返回结果:每次执行低于clientTotal设置的值,故SpringBuilder是线程不安全的类,换成SpringBuffer,执行结果和clientTotal一致,因此SpringBuffer是线程安全的,查看源码得知StringBuffer在方法前添加了synchronized关键字,导致该方法统一时间只能一个线程运行,性能上是有损耗的
SimpleDateFormat->JodaTime
SimpleDateFormat是java提供做日期处理的类
实例
//请求总数
private static int clientTotal=5000;
//同时并发请求的线程数
private static int threadTotal=200;
private static SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
// public static int count=0;
public static void main(String[] args) throws Exception {
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(new Runnable() {
public void run() {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
update();
semaphore.release();
countDownLatch.countDown();
}
});
}
countDownLatch.await();
executorService.shutdown();
// System.out.println("count:"+count);
}
private static void update() {
try {
format.parse("20200227");
} catch (ParseException e) {
e.printStackTrace();
}
}
注:线程安全问题,抛出异常如下,错误原因是SimpleDateFormat不是线程安全对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NE0jQt4E-1582790075842)(/Users/zangchuanjun/Library/Application Support/typora-user-images/image-20200227151947989.png)]
优化写法:使用对象封闭的写法,使用局部变量就可以了,每次声明一个新的SimpleDateFormat对象就可以了
private static void update() {
try {
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
System.out.println(format.parse("2020-02-27"));
} catch (ParseException e) {
e.printStackTrace();
}
}
jodatime日期时间处理类
不属于java下的,需要导包,是线程安全的
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
实例
//请求总数
private static int clientTotal=5000;
//同时并发请求的线程数
private static int threadTotal=200;
// private static SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
private static DateTimeFormatter formatter= DateTimeFormat.forPattern("yyyy-MM-dd");
// public static int count=0;
public static void main(String[] args) throws Exception {
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(new Runnable() {
public void run() {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
update(count);
semaphore.release();
countDownLatch.countDown();
}
});
}
countDownLatch.await();
executorService.shutdown();
// System.out.println("count:"+count);
}
private static void update(int i) {
Date date= DateTime.parse("2020-02-27",formatter).toDate();
log.info("{}:{}",i,date);
}
ArrayList、HashSet、HashMap
ArrayList、Set、HashMap都为非线程安全,线程不安全写法,先检测在执行
线程安全->同步容器