[Dry] Nantong Education Xun Software Development Training: thread safety in Spring

Hi, everybody! Nantong Branch Xun education classroom started it! Today little sister fast dry is recommended for everyone "thread safety in Spring." I know if you can not wait, here please Xun educational software development professional and experienced teacher to give you details. Quick to learn it!

15369493-dae0c9047854b8fe.jpeg

Spring and thread safety

Spring as an IOC / DI container, help us manage the many "bean". But in fact, Spring and there is no guarantee thread safety of these objects, the code required to solve thread safety issues written by the developers themselves.

Spring provides a scope attribute for each bean to represent the scope of the bean. It is the bean life cycle. For example, a scope, the first time it is injected, will be created as a singleton object as a singleton bean, the object will always be multiplexed into the end application.

singleton: the default scope, each scope is singleton bean that will be defined as a singleton object, the object's life cycle is consistent with the Spring IOC container (but will be created when the first injection).

prototype: bean will be created when a new object is defined as each injection.

request: bean is created in a single embodiment each object is defined as the HTTP request, that is to say in a single request are multiplexed with this embodiment a single object.

session: bean objects are created in a single embodiment of a session is defined as a life cycle.

application: bean ServletContext is defined as the life cycle of multiplexing a singleton object.

websocket: bean websocket is defined as the life cycle of a singleton object reuse.

Most objects we handed over the management of Spring are actually some of the stateless objects, such as multithreading and will not lead to the destruction of the state of the object is very suitable default scope Spring, each single case of stateless objects are thread security (it can be said as long as stateless object even a single case of multiple cases are thread-safe, but singleton, after all, continue to create objects overhead savings and the GC).

Stateless object that is not their own state object, naturally, will not because the alternate scheduling multiple threads of their own state led to the destruction thread-safety issues. Stateless objects include DO, DTO, VO these objects anemia solid model data only as we often use, as well as Service, DAO and Controller, these objects and not have their own state, they are only used to perform certain operations. For example, each function of DAO are only provided the CRUD database, but each local database Connection are variable as a function of (local variable in the user stack, the stack itself and the user thread private memory area, so there is no thread-safety issues), throw-off (or returned to the connection pool).

One might think, I do not use request scope can avoid security issues between each request yet? This is completely wrong, because the Controller is a single case of default, a controller object that will be shared by multiple threads, which went back to the security thread. Of course, you can also change the scope of the Controller prototype, in fact, Struts2 did just that, but one thing to note, Spring MVC intercept request is based on the size of each method, which is based on Struts2 each class, so the Controller to create more cases will be frequent and recycling objects, seriously affected the performance.

In fact, by reading the above has been said very clearly, Spring simply do not make any guarantee and measures for multi-thread-safety issues bean. For each bean thread safety issues, simply because each bean's own design. Do not declare any instance variables or state variables in the bean class, so if you must, then use the ThreadLocal variable becomes private to the thread, if the bean instance variables or class variables need to be shared among multiple threads, then only use these methods to achieve thread synchronization synchronized, lock, CAS wait.

The following will be understood by analyzing its source code ThreadLocal achieve the effect, ThreadLocal is a good use of tools, it addresses the security thread (when the variable does not need to be shared by multiple threads) in some cases.

ThreadLocal

ThreadLocal is to provide a tool class thread-local variables for the thread. Its idea is very simple, to provide a copy of thread private variables for the thread, so that multiple threads are free to change their thread-local variables will not affect other threads. But note that, ThreadLocal provide only a shallow copy, if the variable is a reference type, then we must consider whether its internal status will be changed, want to solve this problem by rewriting initialValue the ThreadLocal () function achieve their own deep copy, we recommend the use of ThreadLocal start rewriting the function.

ThreadLocal and as such synchronized lock mechanism is different. First, their application and implementation of ideas is not the same scenario, the lock is more emphasis on how to correctly synchronize multiple threads share a variable, ThreadLocal is to solve the same variable how not to be shared by multiple threads. From a performance overhead perspective, if the lock mechanism is used for space of time, then ThreadLocal is to use space for time.

ThreadLocal contains the inner class called ThreadLocalMap, such as using a linear probe method implemented HashMap. It's key to ThreadLocal objects but also the use WeakReference, ThreadLocalMap it is used to store a copy of the variable.

/**

* ThreadLocalMap is a customized hash map suitable only for

* maintaining thread local values. No operations are exported

* outside of the ThreadLocal class. The class is package private to

* allow declaration of fields in class Thread. To help deal with

* very large and long-lived usages, the hash table entries use

* WeakReferences for keys. However, since reference queues are not

* used, stale entries are guaranteed to be removed only when

* the table starts running out of space.

*/

static class ThreadLocalMap {

/**

* The entries in this hash map extend WeakReference, using

* its main ref field as the key (which is always a

* ThreadLocal object). Note that null keys (i.e. entry.get()

* == null) mean that the key is no longer referenced, so the

* entry can be expunged from table. Such entries are referred to

* as "stale entries" in the code that follows.

*/

static class Entry extends WeakReference<ThreadLocal<? {

/** The value associated with this ThreadLocal. */

Object value;

Entry(ThreadLocal<? k, Object v) {

super(k);

value = v;

}

}

....

}

ThreadLocal contains only three member variables, these three variables are associated with the hash of the strategy ThreadLocalMap.

/**

* ThreadLocals rely on per-thread linear-probe hash maps attached

* to each thread (Thread.threadLocals and

* inheritableThreadLocals). The ThreadLocal objects act as keys,

* searched via threadLocalHashCode. This is a custom hash code

* (useful only within ThreadLocalMaps) that eliminates collisions

* in the common case where consecutively constructed ThreadLocals

* are used by the same threads, while remaining well-behaved in

* less common cases.

*/

private final int threadLocalHashCode = nextHashCode();

/**

* The next hash code to be given out. Updated atomically. Starts at

* zero.

*/

private static AtomicInteger nextHashCode =

new AtomicInteger();

/**

* The difference between successively generated hash codes - turns

* implicit sequential thread-local IDs into near-optimally spread

* multiplicative hash values for power-of-two-sized tables.

*/

private static final int HASH_INCREMENT = 0x61c88647;

/**

* Returns the next hash code.

*/

private static int nextHashCode() {

return nextHashCode.getAndAdd(HASH_INCREMENT);

}

ThreadLocalHashCode instance variable is only used for addressing hashcode, which is generated by the function nextHashCode (), the function simply be generated by a hashcode increment HASH_INCREMENT. As to why this increment 0x61c88647, mainly because of the initial size ThreadLocalMap is 16, each expansion will double the original, so that its capacity is always 2 ^ n, but also to the increment selected 0x61c88647 as possible evenly distributed, reducing the impact of conflict.

/**

* The initial capacity -- MUST be a power of two.

*/

private static final int INITIAL_CAPACITY = 16; /**

* Construct a new map initially containing (firstKey, firstValue).

* ThreadLocalMaps are constructed lazily, so we only create

* one when we have at least one entry to put in it.

*/

ThreadLocalMap(ThreadLocal<? firstKey, Object firstValue) {

table = new Entry[INITIAL_CAPACITY];

int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);

table[i] = new Entry(firstKey, firstValue);

size = 1;

setThreshold(INITIAL_CAPACITY);

}

To obtain a copy of the current thread private variables need to call the get () function. First, it calls getMap () function to get the current thread ThreadLocalMap, this function needs to receive the current thread instance as a parameter. If the resulting ThreadLocalMap is null, then went to call setInitialValue () function to initialize, if not null, it obtained a copy of the map and return variables.

setInitialValue () function will go first call initialValue () function to generate the initial value, the function returns the default null, we can return the variables we want to maintain in the ThreadLocal by rewriting this function. Then, to call getMap () function to obtain ThreadLocalMap, if that map already exists, then use the newly acquired value to cover the old value, otherwise call createMap () function to create a new map.

/**

* Returns the value in the current thread's copy of this

* thread-local variable. If the variable has no value for the

* current thread, it is first initialized to the value returned

* by an invocation of the {@link #initialValue} method.

*

* @return the current thread's value of this thread-local

*/

public T get() {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null) {

ThreadLocalMap.Entry e = map.getEntry(this);

if (e != null) {

@SuppressWarnings("unchecked")

T result = (T)e.value;

return result;

}

}

return setInitialValue();

}

/**

* Variant of set() to establish initialValue. Used instead

* of set() in case user has overridden the set() method.

*

* @return the initial value

*/

private T setInitialValue() {

T value = initialValue();

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null)

map.set(this, value);

else

createMap(t, value);

return value;

}

protected T initialValue() {

return null;

}

ThreadLocal achieve the set () and remove () function than the get () is even simpler, just to get ThreadLocalMap by getMap () and then operate it.

/**

* Sets the current thread's copy of this thread-local variable

* to the specified value. Most subclasses will have no need to

* override this method, relying solely on the {@link #initialValue}

* method to set the values of thread-locals.

*

* @param value the value to be stored in the current thread's copy of

* this thread-local.

*/

public void set(T value) {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null)

map.set(this, value);

else

createMap(t, value);

}

/**

* Removes the current thread's value for this thread-local

* variable. If this thread-local variable is subsequently

* {@linkplain #get read} by the current thread, its value will be

* reinitialized by invoking its {@link #initialValue} method,

* unless its value is {@linkplain #set set} by the current thread

* in the interim. This may result in multiple invocations of the

* {@code initialValue} method in the current thread.

*

* @since 1.5

*/

public void remove() {

ThreadLocalMap m = getMap(Thread.currentThread());

if (m != null)

m.remove(this);

}

getMap () function to achieve createMap () function is also very simple, but by observing these two functions can be found in a secret: ThreadLocalMap is located in a Thread in.

/**

* Get the map associated with a ThreadLocal. Overridden in

* InheritableThreadLocal.

*

* @param t the current thread

* @return the map

*/

ThreadLocalMap getMap(Thread t) {

return t.threadLocals;

}

/**

* Create the map associated with a ThreadLocal. Overridden in

* InheritableThreadLocal.

*

* @param t the current thread

* @param firstValue value for the initial entry of the map

*/

void createMap(Thread t, T firstValue) {

t.threadLocals = new ThreadLocalMap(this, firstValue);

}

// Thread of source

/* ThreadLocal values pertaining to this thread. This map is maintained

* by the ThreadLocal class. */

ThreadLocal.ThreadLocalMap threadLocals = null;

/*

* InheritableThreadLocal values pertaining to this thread. This map is

* maintained by the InheritableThreadLocal class.

*/

ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

Think about it actually can understand the idea of ​​this design. One common method is to store a copy of the variables of each thread through a global thread-safe Map, but this practice has been completely contrary to the intention of ThreadLocal, ThreadLocal design mind is to avoid multiple threads to concurrently access the same object , although it is thread safe. The storage associated with it in each Thread in ThreadLocalMap ThreadLocal is entirely consistent with the idea, and when you want to thread local variables to operate, just need a key to get ThreadLocalMap Thread to Thread in. This design uses a Global Map of the method compared to be taking up a lot of memory space, but because of locks and other thread synchronization method does not need to take extra savings on the consumption of time.

ThreadLocal Memory Leak

We have to consider the case of one kind of memory leak occurs, if ThreadLocal is set to null, and there is no any strong references to it, according to reachability analysis algorithm for garbage collection, ThreadLocal will be recycled. As a result, ThreadLocalMap will contain the key to null Entry, and ThreadLocalMap in Thread, as long delay in the end of the thread, the value of these inaccessible to form a memory leak. To solve this problem, ThreadLocalMap in getEntry (), set () and remove () function will clean up the key to null Entry, in the following getEntry () function source code example.

/**

* Get the entry associated with key. This method

* itself handles only the fast path: a direct hit of existing

* key. It otherwise relays to getEntryAfterMiss. This is

* designed to maximize performance for direct hits, in part

* by making this method readily inlinable.

*

* @param key the thread local object

* @return the entry associated with key, or null if no such

*/

private Entry getEntry(ThreadLocal<? key) {

int i = key.threadLocalHashCode & (table.length - 1);

Entry e = table[i];

if (e != null && e.get() == key)

return e;

else

return getEntryAfterMiss(key, i, e);

}

/**

* Version of getEntry method for use when key is not found in

* its direct hash slot.

*

* @param key the thread local object

* @param i the table index for key's hash code

* @param e the entry at table[i]

* @return the entry associated with key, or null if no such

*/

private Entry getEntryAfterMiss(ThreadLocal<? key, int i, Entry e) {

Entry[] tab = table;

int len = tab.length;

// clean up the key to null Entry

while (e != null) {

ThreadLocal<? k = e.get();

if (k == key)

return e;

if (k == null)

expungeStaleEntry(i);

else

i = nextIndex(i, len);

e = tab[i];

}

return null;

}

In the above, we find ThreadLocalMap the key is a weak reference, so why use a weak reference it? Using strong and weak key references cited in the following key differences:

A strong reference Key : ThreadLocal is set to null, ThreadLocal due ThreadLocalMap holds strong references, if not manually deleted, ThreadLocal will not be recovered, resulting in a memory leak.

Weak references Key : ThreadLocal is set to null, ThreadLocal due ThreadLocalMap hold a weak reference, even if not manually deleted, ThreadLocal still be recovered, ThreadLocalMap after the call set (), getEntry () and remove () function will clear all the time key to null Entry.

But it should be noted that, ThreadLocalMap only contain these passive measures to remedy memory leaks. If you do not call ThreadLocalMap after the set (), getEntry () and remove () function, then there will still be a memory leak problem.

In the case of the thread pool, if not promptly clean up, memory leaks is a small matter, may even cause problems on the program logic. Therefore, in order to safely use ThreadLocal, have to like each use the same lock is unlocked, should call remove after each use ThreadLocal () to clean up the useless Entry.

references

Are Spring objects thread safe? – Stack Overflow:https://link.juejin.im/?target=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F15745140%2Fare-spring-objects-thread-safe

Spring Singleton, Request, Session Beans and Thread Safety | Java Enterprise Ecosystem.:https://link.juejin.im/?target=https%3A%2F%2Ftarunsapra.wordpress.com%2F2011%2F08%2F21%2Fspring-singleton-request-session-beans-and-thread-safety%2F

Spring Framework Documentation:https://link.juejin.im/?target=https%3A%2F%2Fdocs.spring.io%2Fspring%2Fdocs%2Fcurrent%2Fspring-framework-reference%2Findex.html

15369493-bd0bef1eb62ffc9f.jpeg

Thank you for your patience to read, want to want to learn IT software development Nantong classmates help! If you develop a keen interest in learning IT software, welcome to communicate with me. Nantong Branch Education Xun welcome everyone who loves IT software development you that every person has planned for their future career!

Reproduced in: https: //www.jianshu.com/p/0d4eead91f54

Guess you like

Origin blog.csdn.net/weixin_33755557/article/details/91178613