ThreadLocalNormalUsage05,SimpleDateFormat如何做到的线程隔离?

来源:4-5 更好的做法

bfcpzk

2020-01-02

在ThreadLocalNormalUsage05中,打印ThreadLocal和SimpleDateFormat对象,发现都是同一个对象,我的理解是线程池中的10个线程应该是创建了10个ThreadLocalMap,每个map中都存了一个Entry,key是同一个ThreadLocal对象的引用,value也都是同一个SimpleDateFormat对象,并没有看到副本的拷贝,但却保证了线程的隔离,这是如何做到的呢?

public class ThreadLocalNormalUsage05 {

    private static ExecutorService threadPool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
        for (int i = 0 ; i < 1000 ; i++) {
            int finalI = i;
            threadPool.submit(new Runnable() {
                public void run() {
                    String date = new ThreadLocalNormalUsage05().date(finalI);
                    System.out.println(date);
                }
            });
        }
        threadPool.shutdown();
    }

    private String date(int seconds) {
        //单位是毫秒
        Date date = new Date(seconds * 1000);
        SimpleDateFormat sdf = ThreadSafeDateFormatter.dateFormatThreadLocal.get();
        System.out.println(ThreadSafeDateFormatter.dateFormatThreadLocal);
        System.out.println(ThreadSafeDateFormatter.dateFormatThreadLocal.get());
        return sdf.format(date);
    }
}

class ThreadSafeDateFormatter {
    static ThreadLocal<SimpleDateFormat> dateFormatThreadLocal = new ThreadLocal<SimpleDateFormat>(){
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };

    static ThreadLocal<SimpleDateFormat> dateFormatThreadLocal2 = ThreadLocal.withInitial(
            () -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
}
运行结果:
threadlocal.ThreadSafeDateFormatter$1@46600188
threadlocal.ThreadSafeDateFormatter$1@46600188
java.text.SimpleDateFormat@4f76f1a0
threadlocal.ThreadSafeDateFormatter$1@46600188
java.text.SimpleDateFormat@4f76f1a0
threadlocal.ThreadSafeDateFormatter$1@46600188
java.text.SimpleDateFormat@4f76f1a0
threadlocal.ThreadSafeDateFormatter$1@46600188
java.text.SimpleDateFormat@4f76f1a0
threadlocal.ThreadSafeDateFormatter$1@46600188
threadlocal.ThreadSafeDateFormatter$1@46600188
java.text.SimpleDateFormat@4f76f1a0
threadlocal.ThreadSafeDateFormatter$1@46600188
java.text.SimpleDateFormat@4f76f1a0
java.text.SimpleDateFormat@4f76f1a0
1970-01-01 08:00:07
1970-01-01 08:00:02
threadlocal.ThreadSafeDateFormatter$1@46600188
threadlocal.ThreadSafeDateFormatter$1@46600188
java.text.SimpleDateFormat@4f76f1a0
threadlocal.ThreadSafeDateFormatter$1@46600188
java.text.SimpleDateFormat@4f76f1a0
java.text.SimpleDateFormat@4f76f1a0
1970-01-01 08:00:08
1970-01-01 08:00:00
1970-01-01 08:00:01
1970-01-01 08:00:06
1970-01-01 08:00:04
1970-01-01 08:00:09
写回答

2回答

悟空

2020-01-02

示例代码:

    public String date(int seconds) {
        //参数的单位是毫秒,从1970.1.1 00:00:00 GMT计时
        Date date = new Date(1000 * seconds);
//        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat dateFormat = ThreadSafeFormatter.dateFormatThreadLocal2.get();
        System.out.println(
                Thread.currentThread().getName() + ThreadSafeFormatter.dateFormatThreadLocal);
        SimpleDateFormat simpleDateFormat = ThreadSafeFormatter.dateFormatThreadLocal.get();
        System.out.println(Thread.currentThread().getName() + simpleDateFormat.toString());
        System.out.println(
                Thread.currentThread().getName() + System.identityHashCode(simpleDateFormat));

        return dateFormat.format(date);
    }


0
0

bfcpzk

提问者

2020-01-02

如果线程池中10个线程同时访问的还是同一个SimpleDateFormat对象,如何做到的线程安全呢?

0
2
bfcpzk
回复
悟空
明白啦,谢谢老师!
2020-01-03
共2条回复

深度解密Java并发工具,精通JUC,成为并发多面手

JUC全方位讲解,构建并发工具类知识体系

1599 学习 · 573 问题

查看课程