java線程--ThreadLocal的簡單使用

ThreadLocal的簡單使用

public class Test {

    static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<SimpleDateFormat>();

    static class MyTask implements Runnable {
        static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        int i = 0;

        public MyTask(int i) {
            this.i = i;
        }

        @Override
        public void run() {

            if (t1.get() == null) {
                t1.set(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
                try {
                    // synchronized (sdf) {
                    // 在未加鎖的狀況下,極可能會出現異常,sdf 並不是線程安全的,
                    // 在每一個線程中共享的sdf未必能加載完畢
                    // 原子性未能保證
                    Date t2 = sdf.parse("2018-01-29");
                    System.out.println(t2);
                    // }

                    Date t = t1.get().parse("2018-01-29 10:27:" + i % 60);
                    System.out.println(i + ":" + t);
                } catch (ParseException e) {
                    e.printStackTrace();
                }

            }
        }

    }

    public static void main(String[] args) throws InterruptedException {

        MyTask r1 = new MyTask(100);
        ExecutorService exs = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 10; i++) {
            exs.execute(r1);
        }
    }

}

ThreadLocal的時間效率

public class Test {

    public static final int gen_count = 4000000;
    public static final int nthread = 10;
    static ExecutorService exs = Executors.newFixedThreadPool(nthread);

    //多線程共享一個random 對象
    //Random 是線程安全的
    public static Random rnd = new Random(123);
    public static ThreadLocal<Random> tRnd = new ThreadLocal<Random>() {
        @Override
        protected Random initialValue() {

            return new Random(123);
        }
    };

    static class MyTask implements Callable<Long> {

        private int mode = 0;

        public MyTask(int mode) {
            this.mode = mode;
        }

        public Random getRandom() {

            if (mode == 0) {
                return rnd;
            } else if (mode == 1) {
                return tRnd.get();
            }

            return null;

        }

        @Override
        public Long call() throws Exception {

            long b = System.currentTimeMillis();
            for (long i = 0; i < gen_count; i++) {
                getRandom().nextInt();
            }
            long e = System.currentTimeMillis();
            //System.out.println(Thread.currentThread().getName() + "耗時: " + (e - b));
            return e - b;
        }

    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {

        Future<Long>[] futs = new Future[nthread];
        for (int i = 0; i < nthread; i++) {
            futs[i] = exs.submit(new MyTask(0));
        }
        long totaltime = 0;
        for (int i = 0; i < nthread; i++) {
            totaltime += futs[i].get();
        }
        System.out.println("多線程訪問同一個Random實例" + totaltime);

        totaltime = 0;
        for (int i = 0; i < nthread; i++) {
            futs[i] = exs.submit(new MyTask(1));
        }

        for (int i = 0; i < nthread; i++) {
            totaltime += futs[i].get();
        }
        System.out.println("使用ThreadLocal包裝Random實例" + "耗時: " + totaltime);
        exs.shutdown();
    }
}

實驗結果

多線程訪問同一個Random實例耗時: 27669
使用ThreadLocal包裝Random實例耗時: 1285

Thread:ocal實現原理淺析

set 方法

/**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

get方法

/**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
相關文章
相關標籤/搜索