Переменная ThreadLocal не изменяется

У меня есть приведенный ниже код, который использует 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"));
  }
}

Теперь в основном методе я создаю три потока и запускаю их. Для первого потока (поток-1) я изменяю шаблон SimpleDateFormat на гггг/ММ/дд. Поэтому, согласно концепции 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

person thedevd    schedule 25.11.2019    source источник
comment
Класс SimpleDateFormat известен своей проблемой и давно устарел. Не используйте его. Используйте LocalDate и DateTimeFormatter из java.time, современного API даты и времени Java. Они также являются потокобезопасными, поэтому нет необходимости в вашем локальном потоке. Один глобальный DateTimeFormatter подойдет при условии, что вы хотите, чтобы везде был один и тот же формат.   -  person Ole V.V.    schedule 25.11.2019


Ответы (1)


Для первого потока (поток-1) я изменяю шаблон SimpleDateFormat на гггг/ММ/дд.

Нет, ты не такой.

Вы вызываете txn1.changeFormatterToYYYMMDD() в потоке main. Это не thread-1. Всего у вас есть четыре потока: поток, выполняющий метод main, и три потока, которые вы создали отдельно.

Таким образом, единственный шаблон, который вы меняете, никогда не регистрируется.

person Jon Skeet    schedule 25.11.2019
comment
Ох. Я вижу, что это фактически меняет шаблон для основного потока. Спасибо, что указали на это. Но теперь вопрос в том, как изменить шаблон для потока-1 после его запуска? - person thedevd; 25.11.2019
comment
Да, вы абсолютно правы. Это невозможно вне потока, потому что один поток не может видеть переменную threadLocal другого потока. По этой причине изменение шаблона из основного потока фактически ссылалось на локальный поток основного потока, а не на поток-1. Спасибо бро за разъяснения. - person thedevd; 25.11.2019