- 每個線程需要獨享的對象,且這個對象是線程不安全的,所以需要ThreadLocal給每個線程複製一份 eg:Random、SimpleDateFormat 都是線程不安全的;
以下代碼是通過線程池來打印各個線程的時間
`
public static ExecutorService executorService = Executors.newFixedThreadPool(10);
public static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
int finalI = i;
executorService.submit(new Runnable() {
@Override
public void run() {
Date date = TenThreadTest.date(finalI);
System.out.println(simpleDateFormat.format(date));
}
});
}
executorService.shutdown();
}
public static Date date (int seconds) {
return new Date(1000 * seconds);
}
`
以上代碼執行結果
`
1970-01-01 08:00:02
1970-01-01 08:00:06
1970-01-01 08:00:05
1970-01-01 08:00:02
1970-01-01 08:00:02
1970-01-01 08:00:08
1970-01-01 08:00:02
1970-01-01 08:00:02
1970-01-01 08:00:09
1970-01-01 08:00:07
`
大家有沒有發現一個問題就是執行結果中存在重複的時間,根本原因就是 SimpleDateFormat 是線程不安全的,所有的線程共SimpleDateFormat,我們可以通過synchronized加鎖,但是synchronized是阻塞的,如果線程的任務量特別大,效率會特別低;
以下是通過ThreadLocal加持過得實現方式:
十個線程都會有自己的 SimpleDateFormat 都是線程獨享的
`
public static ExecutorService executorService = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
int finalI = i;
executorService.submit(new Runnable() {
@Override
public void run() {
SimpleDateFormat simpleDateFormat = ThreadLocalFormat.simpleDateFormatThreadLocal.get();
Date date = TenThreadTest.date(finalI);
System.out.println(simpleDateFormat.format(date));
}
});
}
executorService.shutdown();
}
public static Date date (int seconds) {
return new Date(1000 * seconds);
}
static class ThreadLocalFormat {
public static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = ThreadLocal.withInitial(() ->
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"));
}
`
- 每個線程內需要全局變量,不需要傳參,可以讓不同的方法直接使用
以下代碼讓當前用戶在當前線程暢通無阻,不需要層層傳遞參數
`
package thread;
public class UsePart2 {
public static void main(String[] args) {
User user = new User();
user.setName("王哈哈");
UserContentHolder.threadLocal.set(user);
new Service1().process();
new Service2().process();
new Service3().process();
}
}
class Service1 {
public void process() {
System.out.println("service1" + UserContentHolder.threadLocal.get().getName());
}
}
class Service2 {
public void process() {
System.out.println("service2" + UserContentHolder.threadLocal.get().getName());
}
}
class Service3 {
public void process() {
System.out.println("service3" + UserContentHolder.threadLocal.get().getName());
}
}
class UserContentHolder{
public static ThreadLocal<User> threadLocal = new ThreadLocal<User>();
}
class User {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
}
`
運行結果:
`
service1王哈哈
service2王哈哈
service3王哈哈
`