Поиск по сайту:

Пример Java ThreadLocal


Java ThreadLocal используется для создания локальных переменных потока. Мы знаем, что все потоки объекта совместно используют его переменные, поэтому переменная не является потокобезопасной. Мы можем использовать синхронизацию для обеспечения безопасности потоков, но если мы хотим избежать синхронизации, мы можем использовать переменные ThreadLocal.

Java ThreadLocal

Пример Java ThreadLocal

Вот небольшой пример, показывающий использование ThreadLocal в java-программе и доказывающий, что у каждого потока есть собственная копия переменной ThreadLocal. ThreadLocalExample.java

package com.journaldev.threads;

import java.text.SimpleDateFormat;
import java.util.Random;

public class ThreadLocalExample implements Runnable{

    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue()
        {
            return new SimpleDateFormat("yyyyMMdd HHmm");
        }
    };
    
    public static void main(String[] args) throws InterruptedException {
        ThreadLocalExample obj = new ThreadLocalExample();
        for(int i=0 ; i<10; i++){
            Thread t = new Thread(obj, ""+i);
            Thread.sleep(new Random().nextInt(1000));
            t.start();
        }
    }

    @Override
    public void run() {
        System.out.println("Thread Name= "+Thread.currentThread().getName()+" default Formatter = "+formatter.get().toPattern());
        try {
            Thread.sleep(new Random().nextInt(1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //formatter pattern is changed here by thread, but it won't reflect to other threads
        formatter.set(new SimpleDateFormat());
        
        System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());
    }

}

Вывод приведенной выше примерной программы java ThreadLocal:

Thread Name= 0 default Formatter = yyyyMMdd HHmm
Thread Name= 1 default Formatter = yyyyMMdd HHmm
Thread Name= 0 formatter = M/d/yy h:mm a
Thread Name= 2 default Formatter = yyyyMMdd HHmm
Thread Name= 1 formatter = M/d/yy h:mm a
Thread Name= 3 default Formatter = yyyyMMdd HHmm
Thread Name= 4 default Formatter = yyyyMMdd HHmm
Thread Name= 4 formatter = M/d/yy h:mm a
Thread Name= 5 default Formatter = yyyyMMdd HHmm
Thread Name= 2 formatter = M/d/yy h:mm a
Thread Name= 3 formatter = M/d/yy h:mm a
Thread Name= 6 default Formatter = yyyyMMdd HHmm
Thread Name= 5 formatter = M/d/yy h:mm a
Thread Name= 6 formatter = M/d/yy h:mm a
Thread Name= 7 default Formatter = yyyyMMdd HHmm
Thread Name= 8 default Formatter = yyyyMMdd HHmm
Thread Name= 8 formatter = M/d/yy h:mm a
Thread Name= 7 formatter = M/d/yy h:mm a
Thread Name= 9 default Formatter = yyyyMMdd HHmm
Thread Name= 9 formatter = M/d/yy h:mm a

Как вы можете видеть из вывода, Thread-0 изменил значение форматирования, но по-прежнему форматер по умолчанию для потока-2 такой же, как и инициализированное значение. Вы можете увидеть тот же шаблон и для других потоков. Обновление: класс ThreadLocal расширен в Java 8 с помощью нового метода withInitial(), который принимает функциональный интерфейс поставщика в качестве аргумента. Таким образом, мы можем использовать лямбда-выражения, чтобы легко создать экземпляр ThreadLocal. Например, приведенная выше переменная ThreadLocal средства форматирования может быть определена в одной строке, как показано ниже:

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

Если вы не знакомы с функциями Java 8, ознакомьтесь с API Doc.