ThreadLocal design principles

1. ThreadLocal

1.1 Introduction

ThreadLocal is an internal thread data storage class, through which you can store data in the specified thread, after the data is stored only in the specified thread can get to the data store, you can not get the data visible to another thread.

It can meet the following requirements:

  • The same variable in a different thread needs to have different copies
  • Often used in static methods, can not be assigned at the time of thread creation

1.2 application scenarios

  • Database connection pool
  • Hibernate的session
  • Other classes are not thread-safe lock for use in multiple threads

1.3 Application Examples

Time-resolved class SimpleDateFormat is a typical example of thread-safe, because at the same time can only support one analytical expression, using only two choices multithreaded environment:

  • Locking access
  • By ThreadLocal, so that thread holds a thread private SimpleDateFormat objects

    private static final ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<>();

    static String format(Date date, String pattern) {
        SimpleDateFormat simpleDateFormat = threadLocal.get();
        if (simpleDateFormat == null) {
            simpleDateFormat = new SimpleDateFormat();
            threadLocal.set(simpleDateFormat);
        }
        simpleDateFormat.applyPattern(pattern);
        return simpleDateFormat.format(date);
    }

2. Design Principles

Next we try to design a program of their own, so that any time a thread can have its own thread private variables. To help understand the evolution of the JDK programs through the design.

Thread private variables there are two places you can choose to save:

  • Internal thread
  • External set

2.1 is stored in the thread

2.1.1 definitions

The first way to think of, is the most straightforward, is to hold private variable by multiple threads Map.

public class ThreadLocalInside extends Thread {
    WeakHashMap<Object, Object> threadLocals = new WeakHashMap<>();
}

2.1.2 Use Case

His own flexible setup key to distinguish between different thread private variables.

    static String format(Date date, String pattern) {
        ThreadLocalInside thread = (ThreadLocalInside) Thread.currentThread();
        Class clazz = SimpleDateFormat.class;
        SimpleDateFormat simpleDateFormat = (SimpleDateFormat) thread.threadLocals.get(clazz);
        if (simpleDateFormat == null) {
            simpleDateFormat = new SimpleDateFormat();
            thread.threadLocals.put(clazz, simpleDateFormat);
        }
        simpleDateFormat.applyPattern(pattern);
        return simpleDateFormat.format(date);
    }

2.1.3 advantage

  • Thread safety. How does the issue of access to the thread.

2.1.4 shortcomings

  • Improper use easy memory footprint is too large. Private variables survival time as long as the threads can not use the garbage collector.
  • coupling. The new API requires coupling thread class.
  • Management inconvenient. If you want to remove a copy of a thread private variables in all threads, very difficult.

2.2 saved in the external collection

2.2.1 code implementation

public class ThreadLocalOutside extends WeakHashMap<Thread, HashMap<Object, Object>> {
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    @Override
    public HashMap<Object, Object> put(Thread key, HashMap<Object, Object> value) {
        lock.writeLock().lock();
        try {
            return super.put(key, value);
        } finally {
            lock.writeLock().unlock();
        }
    }

    public HashMap<Object, Object> get(Thread key) {
        lock.readLock().lock();
        try {
            return super.get(key);
        } finally {
            lock.readLock().unlock();
        }
    }
}

2.2.2 Use Case

    private static final ThreadLocalOutside THREAD_LOCAL_MANAGER = new ThreadLocalOutside();

    static String format(Date date, String pattern) {
        Thread thread = Thread.currentThread();
        HashMap<Object, Object> threadLocalVariable = THREAD_LOCAL_MANAGER.get(thread);
        Class clazz = SimpleDateFormat.class;
        SimpleDateFormat simpleDateFormat = (SimpleDateFormat) threadLocalVariable.get(clazz);
        if (simpleDateFormat == null) {
            simpleDateFormat = new SimpleDateFormat();
            threadLocalVariable.put(clazz, simpleDateFormat);
        }
        simpleDateFormat.applyPattern(pattern);
        return simpleDateFormat.format(date);
    }

2.2.3 advantage

  • Decoupling. Use a separate class to manage external thread private variables do not have to join in the thread api.
  • Easy to manage. You can easily remove all the threads in a private variable.

2.2.4 shortcomings

  • Performance issues. The need to avoid locking thread insecurity.
  • Improper use easy memory footprint is too large. Private variables survival time as long as the threads can not use the garbage collector.

3. JDK design, internal and external integration

The ThreadLocal JDK includes two design ideas above, that is stored in the thread, but it provides an API to manipulate by external class.

Introduces a new design: the use of private variables ThreadLocal object as a set of Key, each ThreadLocal object represents a kind of thread private variables. This design addresses the pain points of managing thread private variables:

  • When you need to have many kinds of thread private variables, how many ThreadLocal object is created, so that the thread private variables management more convenient.
  • When you want to remove a thread private variables in all threads, it can no longer referenced ThreadLocal objects, the other to the garbage collector.

3.1 code implementation

To keep the reader's attention is weak reference implementation details of the hash table dispersion used here instead of ThreadLocal WeakHashMap internal ThreadLocalMap.

3.1.1 Weak References collection

This brief collection features two of the following:

  • If you set Key is no longer referenced by other objects, the garbage collector reclaims out of this Key object.
  • When you call put (), get () and other methods, will be deleted by the way hash table in the elements, that Key object has been garbage.
  • When a hash collision, WeakHashMap use the list method, ThreadLocalMap using open addressing method to resolve the conflict (use an array to save memory), the advantage is simple.

3.1.2 cottage version of the JDK implementation

public class Thread2 extends Thread {
    //ThreadLocal作为key,一个ThreadLocal代表一种线程私有变量
    WeakHashMap<ThreadLocal2, Object> threadLocals;
}

class ThreadLocal2<T> {
    //模板方法
    protected T initialValue() {
        return null;
    }

    public T get() {
        Thread2 thread = (Thread2) Thread.currentThread();
        WeakHashMap<ThreadLocal2, Object> threadLocalMap = thread.threadLocals;
        if (threadLocalMap != null) {
            Object value = threadLocalMap.get(this);
            if (value != null) {
                return (T) value;
            }
        }
        T value = initialValue();
        if (threadLocalMap != null) {
            threadLocalMap.put(this, value);
        } else {
            //懒加载,大部分线程不使用threadLocal,因此能节约不少内存
            thread.threadLocals = new WeakHashMap<>();
            thread.threadLocals.put(this, value);
        }
        return value;
    }

    public void set(T object) {
        Thread2 thread = (Thread2) Thread.currentThread();
        WeakHashMap<ThreadLocal2, Object> threadLocalMap = thread.threadLocals;
        if (threadLocalMap != null) {
            threadLocalMap.put(this, object);
        } else {
            //懒加载,大部分线程不使用threadLocal,因此能节约不少内存
            thread.threadLocals = new WeakHashMap<>();
            thread.threadLocals.put(this, initialValue());
        }
    }
}

3.2 Use Case

ThreadLocal to use almost exactly the same and JDK to achieve it

    private static final ThreadLocal2<SimpleDateFormat> threadLocal = new ThreadLocal2<>() ;

    static String format(Date date, String pattern) {
        SimpleDateFormat simpleDateFormat = threadLocal.get();
        if (simpleDateFormat == null) {
            simpleDateFormat = new SimpleDateFormat();
            threadLocal.set(simpleDateFormat);
        }
        simpleDateFormat.applyPattern(pattern);
        return simpleDateFormat.format(date);
    }

3.3 advantage

  • High performance: The collection is stored in the thread thread private variables, no lock.
  • Decoupling: external object provides API.
  • Use JDK garbage collection mechanism: Key external object as a hash table in the thread, but with weak references to hold Key, when the external object is no longer referenced by other objects and has been garbage collected will be deleted by the way hash tables, the elements with the proviso that Key object has been garbage.
  • Easy to manage. Can easily remove all the threads in a private variable, simply delete references to the corresponding threadLocal.

Simply select the essence to its dregs.

3.4 shortcomings

  • Improper use easy memory footprint is too large. Private variables survival time as long threads.

Guess you like

Origin www.cnblogs.com/datartvinci/p/11069913.html