【问题标题】:ThreadLocal variable is not changedThreadLocal 变量没有改变
【发布时间】:2019-11-25 11:18:13
【问题描述】:

我有下面给出的代码,它使用 ThreadLocal 为每个线程存储一个单独的 SimpleDateFormat 副本。我的初始模式是 MM/dd/yyyy。

class PerThreadLocalVariables {
   public static final ThreadLocal<SimpleDateFormat> THREAD_LOCAL_FORMATTER = ThreadLocal
        .withInitial(() -> new SimpleDateFormat("MM/dd/yyyy"));
}

我有以下任务“TransactionService”,它使用 ThreadLocal 实例来记录 txn 的开始日期。这个类还有一个方法来改变一个特定任务的 SimpleDateFormat -

class TransactionService implements Runnable {

  @Override
  public void run()
  {
    System.out.println(Thread.currentThread().getName() + ": startDate= "
            + PerThreadLocalVariables.THREAD_LOCAL_FORMATTER.get().format(new Date()));

    try
    {
        Thread.sleep(10000);
        System.out.println("After some time ... " + Thread.currentThread().getName() + ": date pattern= "
                + PerThreadLocalVariables.THREAD_LOCAL_FORMATTER.get().toPattern());

    }
    catch( InterruptedException e )
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

  }

  public void changeFormatterToYYYMMDD()
  {
    // Changing the thread local variable will not affect variable of other thread.
    PerThreadLocalVariables.THREAD_LOCAL_FORMATTER.set(new SimpleDateFormat("yyyy/MM/dd"));
  }
}

现在在 main 方法中,我创建三个线程并启动它们,对于第一个线程(线程 1),我将 SimpleDateFormat 模式更改为 yyyy/MM/dd。因此,根据 ThreadLocal 概念的更改,这不应影响其他两个线程(线程 2 和线程 3)使用的模式。但问题是它甚至没有改变线程 1 的模式。我仍然看到初始模式,即 MM/dd/yyyy。我不确定我在这里做错了什么 -

public class ThreadLocalDemo {

  public static void main( String[] args ) throws InterruptedException
  {
    TransactionService txn1 = new TransactionService();
    new Thread(txn1, "thread-1").start();

    Thread.sleep(2000);
    new Thread(new TransactionService(), "thread-2").start();
    Thread.sleep(5000);
    new Thread(new TransactionService(), "thread-3").start();

    txn1.changeFormatterToYYYMMDD(); // this will not affect thread-2 and thread-3's simpleDateFormat pattern
    System.out.println("Changed SimpleDateFormat pattern to yyyy/MM/dd for thread-1");

  }
}

输出 - (您仍然可以看到线程 1 的模式是相同的,即 MM/dd/yyyy,它应该根据代码更改为 yyyy/MM/dd)

thread-1: startDate= 11/25/2019
thread-2: startDate= 11/25/2019
Changed SimpleDateFormat pattern to yyyy/MM/dd for thread-1
thread-3: startDate= 11/25/2019
After some time ... thread-1: date pattern= MM/dd/yyyy
After some time ... thread-2: date pattern= MM/dd/yyyy
After some time ... thread-3: date pattern= MM/dd/yyyy

【问题讨论】:

  • SimpleDateFormat 类是出了名的麻烦和过时。不要使用它。使用现代 Java 日期和时间 API java.time 中的 LocalDateDateTimeFormatter。它们是 akso 线程安全的,因此不需要您的线程本地。一个全局的DateTimeFormatter 就可以了,前提是您希望在所有地方都使用相同的格式。

标签: java multithreading simpledateformat thread-local


【解决方案1】:

对于第一个线程(线程 1),我将 SimpleDateFormat 模式更改为 yyyy/MM/dd。

不,你不是。

你在 main 线程中调用txn1.changeFormatterToYYYMMDD()。那不是thread-1。您总共有 四个 线程:执行main 方法的线程,以及您单独创建的三个线程。

因此,您要更改的唯一模式是永远不会记录的模式。

【讨论】:

  • 哦。我看到它实际上正在改变主线程的模式。感谢您指出这一点。但现在的问题是如何在 thread-1 启动后更改模式?
  • 是的,你完全正确。这在线程之外是不可能的,因为一个线程看不到其他线程的 threadLocal 变量。这就是从主线程更改模式实际上只指主线程的线程本地而不是线程1的原因。感谢兄弟的澄清。
猜你喜欢
  • 2014-12-02
  • 1970-01-01
  • 2010-10-11
  • 1970-01-01
  • 2018-01-20
  • 1970-01-01
  • 2022-12-06
  • 1970-01-01
相关资源
最近更新 更多