Java 线程本地示例

Java ThreadLocal 用于创建线程本地变量,我们知道一个对象的所有线程都共享它的变量,所以变量不是线程安全的,我们可以使用同步来确保线程安全,但如果我们想要避免同步,我们可以使用‘ThreadLocal’变量。

Java ThreadLocal 应用程序

ThreadLocal, Java ThreadLocal Every thread has it's own ThreadLocal variable and they can use it's get() and set() methods to get the default value or change it's value local to Thread. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread.

Java ThreadLocal 示例

以下是一個小例子,顯示了 Java 程式中 ThreadLocal 的使用,並證明每個 thread 都有其自己的 ThreadLocal 變數副本。

 1package com.journaldev.threads;
 2
 3import java.text.SimpleDateFormat;
 4import java.util.Random;
 5
 6public class ThreadLocalExample implements Runnable{
 7
 8    // SimpleDateFormat is not thread-safe, so give one to each thread
 9    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
10        @Override
11        protected SimpleDateFormat initialValue()
12        {
13            return new SimpleDateFormat("yyyyMMdd HHmm");
14        }
15    };
16
17    public static void main(String[] args) throws InterruptedException {
18        ThreadLocalExample obj = new ThreadLocalExample();
19        for(int i=0 ; i<10; i++){
20            Thread t = new Thread(obj, ""+i);
21            Thread.sleep(new Random().nextInt(1000));
22            t.start();
23        }
24    }
25
26    @Override
27    public void run() {
28        System.out.println("Thread Name= "+Thread.currentThread().getName()+" default Formatter = "+formatter.get().toPattern());
29        try {
30            Thread.sleep(new Random().nextInt(1000));
31        } catch (InterruptedException e) {
32            e.printStackTrace();
33        }
34        //formatter pattern is changed here by thread, but it won't reflect to other threads
35        formatter.set(new SimpleDateFormat());
36
37        System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());
38    }
39
40}

上面的 Java ThreadLocal 示例程序的输出是:

 1Thread Name= 0 default Formatter = yyyyMMdd HHmm
 2Thread Name= 1 default Formatter = yyyyMMdd HHmm
 3Thread Name= 0 formatter = M/d/yy h:mm a
 4Thread Name= 2 default Formatter = yyyyMMdd HHmm
 5Thread Name= 1 formatter = M/d/yy h:mm a
 6Thread Name= 3 default Formatter = yyyyMMdd HHmm
 7Thread Name= 4 default Formatter = yyyyMMdd HHmm
 8Thread Name= 4 formatter = M/d/yy h:mm a
 9Thread Name= 5 default Formatter = yyyyMMdd HHmm
10Thread Name= 2 formatter = M/d/yy h:mm a
11Thread Name= 3 formatter = M/d/yy h:mm a
12Thread Name= 6 default Formatter = yyyyMMdd HHmm
13Thread Name= 5 formatter = M/d/yy h:mm a
14Thread Name= 6 formatter = M/d/yy h:mm a
15Thread Name= 7 default Formatter = yyyyMMdd HHmm
16Thread Name= 8 default Formatter = yyyyMMdd HHmm
17Thread Name= 8 formatter = M/d/yy h:mm a
18Thread Name= 7 formatter = M/d/yy h:mm a
19Thread Name= 9 default Formatter = yyyyMMdd HHmm
20Thread Name= 9 formatter = M/d/yy h:mm a

正如你可以从输出中看到的那样,Thread-0 已经改变了 formater 的值,但 thread-2 默认的 formater 与初始化值相同。 您也可以看到其他 threads 的相同模式。 Update:ThreadLocal 类在 Java 8 中被扩展到一种新的方法 withInitial(),该方法将供应商的功能界面作为论点。 因此,我们可以使用 lambda 表达式来轻松创建 ThreadLocal 实例。

1private static final ThreadLocal<SimpleDateFormat> formatter = 
2    ThreadLocal.<SimpleDateFormat>withInitial
3    (() -> {return new SimpleDateFormat("yyyyMMdd HHmm");});

如果您对 Java 8 功能不熟悉,请参阅 [Java 8 Features](/community/tutorials/java-8-features-with-examples Java 8 Features)和 [Java 8 Functional Interfaces](/community/tutorials/java-8-functional-interfaces Java 8 Functional Interfaces)。

Published At
Categories with 技术
Tagged with
comments powered by Disqus