Поиск…


замечания

Лучше всего использовать объекты, зависящие от внутренних элементов при вызове вызова, но в противном случае они не имеют аналогов, например SimpleDateFormat , Marshaller

Для использования Random ThreadLocal рассмотрите возможность использования ThreadLocalRandom

Функциональная инициализация ThreadLocal Java 8

public static class ThreadLocalExample
{
    private static final ThreadLocal<SimpleDateFormat> format = 
        ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMdd_HHmm"));

    public String formatDate(Date date)
    {
        return format.get().format(date);
    }
}

Основное использование ThreadLocal

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

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

Следующий фрагмент кода показывает, как его можно использовать:

Каждый поток имеет собственную переменную ThreadLocal и они могут использовать методы get() и set() для получения значения по умолчанию или изменения локального значения для Thread.

ThreadLocal обычно являются частные статические поля в классах, которые хотят связать состояние с потоком.

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

package com.examples.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
 // 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.set(new SimpleDateFormat());
        
        System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());
    }

}

Выход:

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 изменил значение форматирования, но форматир по умолчанию по-умолчанию-нить-то же, что и инициализированное значение.

Несколько потоков с одним общим объектом

В этом примере у нас есть только один объект, но он разделяется между / выполняется на разных потоках. Обычное использование полей для сохранения состояния было бы невозможно, потому что другой поток тоже увидит это (или, вероятно, не увидит).

public class Test {
    public static void main(String[] args) {
        Foo foo = new Foo();
        new Thread(foo, "Thread 1").start();
        new Thread(foo, "Thread 2").start();
    }
}

В Foo мы начинаем отсчет с нуля. Вместо сохранения состояния в поле мы сохраняем наше текущее число в объекте ThreadLocal, который статически доступен. Обратите внимание, что синхронизация в этом примере не связана с использованием ThreadLocal, а скорее обеспечивает лучший выход на консоль.

public class Foo implements Runnable {
    private static final int ITERATIONS = 10;
    private static final ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };

    @Override
    public void run() {
        for (int i = 0; i < ITERATIONS; i++) {
            synchronized (threadLocal) {
                //Although accessing a static field, we get our own (previously saved) value.
                int value = threadLocal.get();
                System.out.println(Thread.currentThread().getName() + ": " + value);
                
                //Update our own variable
                threadLocal.set(value + 1);

                try {
                    threadLocal.notifyAll();
                    if (i < ITERATIONS - 1) {
                        threadLocal.wait();
                    }
                } catch (InterruptedException ex) {
                }
            }
        }
    }
}

Из вывода видно, что каждый поток подсчитывает для себя и не использует значение другого:

Thread 1: 0
Thread 2: 0
Thread 1: 1
Thread 2: 1
Thread 1: 2
Thread 2: 2
Thread 1: 3
Thread 2: 3
Thread 1: 4
Thread 2: 4
Thread 1: 5
Thread 2: 5
Thread 1: 6
Thread 2: 6
Thread 1: 7
Thread 2: 7
Thread 1: 8
Thread 2: 8
Thread 1: 9
Thread 2: 9


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow