当前位置:网站首页>[JUC series] ThreadLocal of synchronization tool class
[JUC series] ThreadLocal of synchronization tool class
2022-06-29 12:22:00 【Gu Dong】
ThreadLocal analysis
List of articles
ThreadLocal Definition
This provides Thread-local variable . This variable is different from the general variable , Because every access to this variable ( adopt ThreadLocal Of get or set Method ) All threads have their own 、 Independently initialized variable copies .ThreadLocal An instance is usually a private static field in a class that wants to associate a state with a thread ( for example , user ID Or business ID).
As long as the thread is active and ThreadLocal Instance can access , Each thread holds an implicit reference to a copy of its thread local variable ; After the thread disappears , All copies of its thread local instances will be garbage collected ( Unless there are other references to these copies ).
Example
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadLocalDemo {
private static final ThreadLocal<String> THREAD_LOCAL_1 = ThreadLocal.withInitial(() -> "0s");
private static final ThreadLocal<String> THREAD_LOCAL_2 = ThreadLocal.withInitial(() -> "00s");
private static final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(10);
private static final ThreadPoolExecutor POOL_EXECUTOR = initThreadPool(5, 10, 1000);
/** * The worker thread */
public static class WorkerThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger nextId = new AtomicInteger(1);
WorkerThreadFactory(String whatFeatureOfGroup) {
this.namePrefix = "From WorkerThreadFactory's " + whatFeatureOfGroup + "-Worker-";
}
@Override
public Thread newThread(Runnable task) {
String name = namePrefix + nextId.getAndIncrement();
return new Thread(null, task, name, 0);
}
}
/** * Initializes the thread pool */
public static ThreadPoolExecutor initThreadPool(int corePoolSize, int maxPoolSize, long keepAliveTime) {
return new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1000),
new WorkerThreadFactory("ThreadLocalDemo"),
new ThreadPoolExecutor.AbortPolicy());
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
int finalI = i + 1;
POOL_EXECUTOR.execute(() -> {
System.out.println("[" + new SimpleDateFormat("HH:mm:ss.SSS").format(new Date())
+ "]--[" + Thread.currentThread().getName() + "] THREAD_LOCAL_1, threadId:" + Thread.currentThread().getId() + ", " + THREAD_LOCAL_1.get());
System.out.println("[" + new SimpleDateFormat("HH:mm:ss.SSS").format(new Date())
+ "]--[" + Thread.currentThread().getName() + "] THREAD_LOCAL_2, threadId:" + Thread.currentThread().getId() + ", " + THREAD_LOCAL_2.get());
THREAD_LOCAL_1.set("THREAD_LOCAL_1 is " + finalI);
THREAD_LOCAL_2.set("THREAD_LOCAL_2 is " + finalI);
System.out.println("[" + new SimpleDateFormat("HH:mm:ss.SSS").format(new Date())
+ "]--[" + Thread.currentThread().getName() + "] THREAD_LOCAL_1, threadId:" + Thread.currentThread().getId() + ", " + THREAD_LOCAL_1.get());
System.out.println("[" + new SimpleDateFormat("HH:mm:ss.SSS").format(new Date())
+ "]--[" + Thread.currentThread().getName() + "] THREAD_LOCAL_2, threadId:" + Thread.currentThread().getId() + ", " + THREAD_LOCAL_2.get());
THREAD_LOCAL_1.remove();
THREAD_LOCAL_2.remove();
COUNT_DOWN_LATCH.countDown();
});
}
if (COUNT_DOWN_LATCH.await(2, TimeUnit.MINUTES)) {
System.out.println("[" + new SimpleDateFormat("HH:mm:ss.SSS").format(new Date()) + "]--[" + Thread.currentThread().getName() + "] is over.");
}
POOL_EXECUTOR.shutdown();
}
}
Execution results
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-3] THREAD_LOCAL_1, threadId:13, 0s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-4] THREAD_LOCAL_1, threadId:14, 0s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-1] THREAD_LOCAL_1, threadId:11, 0s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-3] THREAD_LOCAL_2, threadId:13, 00s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-1] THREAD_LOCAL_2, threadId:11, 00s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-3] THREAD_LOCAL_1, threadId:13, THREAD_LOCAL_1 is 3
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-2] THREAD_LOCAL_1, threadId:12, 0s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-3] THREAD_LOCAL_2, threadId:13, THREAD_LOCAL_2 is 3
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-5] THREAD_LOCAL_1, threadId:15, 0s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-3] THREAD_LOCAL_1, threadId:13, 0s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-5] THREAD_LOCAL_2, threadId:15, 00s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-3] THREAD_LOCAL_2, threadId:13, 00s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-2] THREAD_LOCAL_2, threadId:12, 00s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-3] THREAD_LOCAL_1, threadId:13, THREAD_LOCAL_1 is 6
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-1] THREAD_LOCAL_1, threadId:11, THREAD_LOCAL_1 is 1
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-4] THREAD_LOCAL_2, threadId:14, 00s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-1] THREAD_LOCAL_2, threadId:11, THREAD_LOCAL_2 is 1
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-3] THREAD_LOCAL_2, threadId:13, THREAD_LOCAL_2 is 6
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-4] THREAD_LOCAL_1, threadId:14, THREAD_LOCAL_1 is 4
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-1] THREAD_LOCAL_1, threadId:11, 0s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-1] THREAD_LOCAL_2, threadId:11, 00s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-4] THREAD_LOCAL_2, threadId:14, THREAD_LOCAL_2 is 4
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-1] THREAD_LOCAL_1, threadId:11, THREAD_LOCAL_1 is 7
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-4] THREAD_LOCAL_1, threadId:14, 0s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-1] THREAD_LOCAL_2, threadId:11, THREAD_LOCAL_2 is 7
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-4] THREAD_LOCAL_2, threadId:14, 00s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-1] THREAD_LOCAL_1, threadId:11, 0s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-4] THREAD_LOCAL_1, threadId:14, THREAD_LOCAL_1 is 9
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-1] THREAD_LOCAL_2, threadId:11, 00s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-4] THREAD_LOCAL_2, threadId:14, THREAD_LOCAL_2 is 9
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-1] THREAD_LOCAL_1, threadId:11, THREAD_LOCAL_1 is 10
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-1] THREAD_LOCAL_2, threadId:11, THREAD_LOCAL_2 is 10
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-2] THREAD_LOCAL_1, threadId:12, THREAD_LOCAL_1 is 2
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-2] THREAD_LOCAL_2, threadId:12, THREAD_LOCAL_2 is 2
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-5] THREAD_LOCAL_1, threadId:15, THREAD_LOCAL_1 is 5
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-3] THREAD_LOCAL_1, threadId:13, 0s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-5] THREAD_LOCAL_2, threadId:15, THREAD_LOCAL_2 is 5
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-3] THREAD_LOCAL_2, threadId:13, 00s
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-3] THREAD_LOCAL_1, threadId:13, THREAD_LOCAL_1 is 8
[17:59:01.646]--[From WorkerThreadFactory's ThreadLocalDemo-Worker-3] THREAD_LOCAL_2, threadId:13, THREAD_LOCAL_2 is 8
[17:59:01.646]--[main] is over.
form
Inner class SuppliedThreadLocal
ThreadLocal An extension of , Get its initial value from the specified supplier .
static final class SuppliedThreadLocal<T> extends ThreadLocal<T> {
private final Supplier<? extends T> supplier;
SuppliedThreadLocal(Supplier<? extends T> supplier) {
this.supplier = Objects.requireNonNull(supplier);
}
@Override
protected T initialValue() {
return supplier.get();
}
}
Inner class ThreadLocalMap
ThreadLocalMap Is a custom hash map , Only for maintaining thread local values . Not in ThreadLocal Class . This class is package private , To allow in class Thread Declare fields in ,ThreadLocal.ThreadLocalMap threadLocals. The hash table Entry Inherited WeakReferences As key, its key The value of is ThreadLocal,value by ThreadLocal Corresponding value . threadLocal.set(5) Will threadLocal and 5 Stored in the thread as a key value pair threadLocals in .
Construction method
This is an empty constructor , If you need to set the initial value , You can call withInitial.
public ThreadLocal() {
}
public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
return new SuppliedThreadLocal<>(supplier);
}
The core approach
| Method name | describe |
|---|---|
set(T value) | Sets the current thread copy of this thread local variable to the specified value . Most subclasses do not need to override this method , Rely solely on initialValue Method to set the value of thread local variables . |
T get() | Returns the value in the current thread copy of this thread local variable . If the variable has no value for the current thread , It is initialized to call initialValue The value returned by the . |
void remove() | Delete the current thread value of this thread local variable . If this thread local variable is subsequently read by the current thread , Its value will be determined by calling its initialValue Method reinitializes , Unless its value is set in the middle by the current thread . This may result in multiple calls in the current thread initialValue Method . |
set process analysis
void set(T value)
Set the value for the copy of the current thread in the thread part
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
- Get the current thread first , adopt getMap Method to get the of the corresponding thread threadLocals Variable
- If threadLocals Variable is not empty , Call set Method to set the thread local variable copy of the current thread value
- If threadLocals The variable is empty , Call createMap Method , establish ThreadLocalMap, It also sets the value of the thread local variable copy . In the ThreadLocalMap Object assigned to threadLocals Variable .
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
Thread Class threadLocals
/* Related to this thread ThreadLocal value . This mapping is by ThreadLocal Class maintenance . */
ThreadLocal.ThreadLocalMap threadLocals = null;
set(ThreadLocal<?> key, Object value)
private void set(ThreadLocal<?> key, Object value) {
//
Entry[] tab = table;
int len = tab.length;
// 1. adopt key Of hashcode Calculate the location of the index
int i = key.threadLocalHashCode & (len-1);
// 2. Traverse from the index position , adopt nextIndex Method to find the next index location
for (Entry e = tab[i];
e != null; // What does this line of code mean ?
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
// When key And Entry[] Array k identical , Update value.
if (k == key) {
e.value = value;
return;
}
// If you traverse to a Entry Of k It's empty , It needs to be emptied key by null Of Entry
if (k == null) {
// Keep looking for key The stored subscript of , And clean up key Empty Entry
replaceStaleEntry(key, value, i);
return;
}
}
// If you pass nextIndex Find an empty location ( The representative did not find key same ), Then put the element in this position
tab[i] = new Entry(key, value);
int sz = ++size;
// call cleanSomeSlots Methods to clean up key by null Of Entry, And judge whether expansion is needed , Call... If necessary rehash Methods to expand capacity
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
nextIndex(int i, int len)
/** stay len Find... In length i The subscript after that */
private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
}
replaceStaleEntry(ThreadLocal<?> key, Object value, int staleSlot)
private void replaceStaleEntry(ThreadLocal<?> key, Object value, int staleSlot) {
Entry[] tab = table;
int len = tab.length;
Entry e;
// Clear the start position of the element
int slotToExpunge = staleSlot;
// From the position staleSlot Traversal forward , Until I met Entry It's empty
for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null; i = prevIndex(i, len))
if (e.get() == null)
slotToExpunge = i; // use staleSlot Record the top of the array key by null The location of i)
// From the position staleSlot Traverse backward , Until I met Entry It's empty
for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) {
ThreadLocal<?> k = e.get();
// If transmitted key And ergodic i Of key identical
if (k == key) {
// to update i Location Entry Of value value
e.value = value;
// In exchange for i Position and staleSlot The element of location (staleSlot The position is in the front , Is the element to be cleared )
tab[i] = tab[staleSlot];
tab[staleSlot] = e;
// If equal , Then represent staleSlot There is no... In the previous subscript key by null Of , What needs to be cleared is that the current subscript is i The elements of
if (slotToExpunge == staleSlot)
slotToExpunge = i;
// from slotToExpunge Position starts to clear key Empty elements
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
return;
}
// Traversing key==null also staleSlot There is no... In the previous subscript key by null Of , Then use staleSlot Record the top of the array key by null The location of i
if (k == null && slotToExpunge == staleSlot)
slotToExpunge = i;
}
// The code goes here to explain , There is no corresponding key, Need to be in staleSlot Create a new location Entry
tab[staleSlot].value = null;
tab[staleSlot] = new Entry(key, value);
// If set up , Note that there are other positions in the array key by null To deal with
if (slotToExpunge != staleSlot)
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
}
cleanSomeSlots(int i, int n)
private boolean cleanSomeSlots(int i, int n) {
boolean removed = false;
Entry[] tab = table;
int len = tab.length;
do {
// from i To traverse the
i = nextIndex(i, len);
Entry e = tab[i];
// Found Entry Not empty , however key by null Of Entry
if (e != null && e.get() == null) {
n = len; // Reset n
removed = true; // Element remove identity
i = expungeStaleEntry(i); //
}
} while ( (n >>>= 1) != 0);
return removed;
}
expungeStaleEntry(int staleSlot)
private int expungeStaleEntry(int staleSlot) {
Entry[] tab = table;
int len = tab.length;
// expunge entry at staleSlot
tab[staleSlot].value = null; // On the array staleSlot Empty object for position
tab[staleSlot] = null;
size--; // Reduce the number of arrays 1
// Rehash until we encounter null
Entry e;
int i;
// staleSlot Continue traversing
for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) {
ThreadLocal<?> k = e.get();
// If you find key Empty , Also empty
if (k == null) {
e.value = null;
tab[i] = null;
size--;
} else {
// Current Entry Of key Not empty
// Recalculate the Entry Index position of
int h = k.threadLocalHashCode & (len - 1);
// If the index location is not the current index location i
if (h != i) {
// take i Position empty
tab[i] = null;
// If at this time h If there are other elements in the location, continue to find the appropriate location , take e place .
while (tab[h] != null)
h = nextIndex(h, len);
tab[h] = e;
}
}
}
return i;
}
Update and expand
private void rehash() {
// call expungeStaleEntries Method ( The method and expungeStaleEntry similar , Just expand the search scope to the entire table ) clear key Empty Entry
expungeStaleEntries();
// If after cleaning size Is a threshold value 3/4, namely size Of 1/2, Then expand the capacity .
if (size >= threshold - threshold / 4)
resize();
}
private void resize() {
Entry[] oldTab = table;
int oldLen = oldTab.length;
// The new length is the old one 2 times
int newLen = oldLen * 2;
Entry[] newTab = new Entry[newLen];
// Number of elements processed , Number of valid elements
int count = 0;
// Traverse all elements
for (int j = 0; j < oldLen; ++j) {
Entry e = oldTab[j];
if (e != null) {
ThreadLocal<?> k = e.get();
// if key It's empty , Will be for value Also set null
if (k == null) {
e.value = null; // Help the GC
} else {
// by e Calculate the index position of the new table
int h = k.threadLocalHashCode & (newLen - 1);
// h The position of may have value , Just look for the right place again
while (newTab[h] != null)
h = nextIndex(h, newLen);
// Put the element e Put it in h Location
newTab[h] = e;
count++;
}
}
}
// Set the threshold for new table expansion
setThreshold(newLen);
// to update size
size = count;
// to update table
table = newTab;
}
createMap(Thread t, T firstValue)
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
get process analysis
get()
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();
}
Follow
setIn the same way , Get the current thread first , ReusegetMapMethod to get thethreadLocalsVariableIf
threadLocalsNot empty , Will callgetMethodicalThreadLocalAskey, callgetEntryMethod to find the correspondingEntry.If
threadLocalsEmpty or target not foundEntry, CallsetInitialValueMethod to initialize .
setInitialValue()
And set Methods have only initialization differences
private T setInitialValue() {
T value = initialValue(); // The default is null
Thread t = Thread.currentThread();
// Get the current thread's `threadLocals` Variable
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
getEntry(ThreadLocal<?> key)
private Entry getEntry(ThreadLocal<?> key) {
// Calculation key For the index position of
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
// If we find the corresponding key With the incoming key equal , Then return to .
if (e != null && e.get() == key)
return e;
else
// if e by null perhaps e Corresponding key With the incoming key atypism , Then keep looking
return getEntryAfterMiss(key, i, e);
}
getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e)
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;
// if e If it is not empty, continue to traverse to find
while (e != null) {
ThreadLocal<?> k = e.get();
// Find the target Entry Then return to .
if (k == key)
return e;
// If you find key by null, The clear logic is triggered
if (k == null)
expungeStaleEntry(i);
else
// Find the next location , Get the corresponding Entry
i = nextIndex(i, len);
e = tab[i];
}
// If you can't find it null
return null;
}
remove process analysis
remove()
public void remove() {
// Gets the current thread's ThreadLocalMap
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
- Gets the current thread's threadLocals attribute , If it's not empty , Will key For the current ThreadLocal Key value pairs of are removed , At the same time, it will call
expungeStaleEntry()Method to remove key by null Of Entry.
remove(ThreadLocal<?> key)
private void remove(ThreadLocal<?> key) {
Entry[] tab = table;
int len = tab.length;
// according to hashCode Calculate the current ThreadLocal Index position of
int i = key.threadLocalHashCode & (len-1);
// from i To traverse the , until Entry by null
for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
// Find the corresponding key
if (e.get() == key) {
// clear() Method will be cleared key References to
e.clear();
// from i Start clearing key by null The elements of
expungeStaleEntry(i);
return;
}
}
}
Memory leak
Memory leak (Memory Leak) It refers to the heap memory that has been dynamically allocated in the program. For some reason, the program is not released or cannot be released , Cause the waste of system memory , Causes the procedure to run the speed to slow down even the system crashes and so on the serious consequence .
* out of memory (Out Of Memory, abbreviation OOM)* It means that there is too much memory in the application system that cannot be recycled or used , Finally, the memory used for program running is larger than the maximum memory provided .
Excessive memory leaks can cause memory overflows .
ThreadLocalMap Use ThreadLocal As a weak reference to Entry Of key, If one ThreadLocal There is no external strong reference to it , Next system GC when , This ThreadLocal It's bound to be recycled , thus ,ThreadLocalMap Will appear in key by null Of Entry, There's no way to visit these key by null Of Entry Of value.
If the current thread has been running , And never execute get、set、remove Method , these key by null Of Entry Of value There will always be a strong reference chain :Thread Ref -> Thread -> ThreadLocalMap -> Entry -> value, Lead to these key by null Of Entry Of value Never recycle , Memory leak .
The total memory of a memory leak is In each thread key by null Of value The sum of .
How to avoid memory leaks
To avoid that , We can use it after ThreadLocal after , Manual call remove Method , To avoid memory leaks .
THREAD_LOCAL_1.remove();
THREAD_LOCAL_2.remove();
Use scenarios
Each in each thread maintains a sequence number
public class SerialNum {
// The next serial number to be assigned
private static int nextSerialNum = 0;
private static ThreadLocal serialNum = new ThreadLocal() {
protected synchronized Object initialValue() {
return new Integer(nextSerialNum++);
}
};
public static int get() {
return ((Integer) (serialNum.get())).intValue();
}
}
session Management of
private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
return s;
}
Used in thread pool threadlocal
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadLocalDemo {
private static final ThreadLocal<String> THREAD_LOCAL_1 = ThreadLocal.withInitial(() -> "0s");
private static final ThreadLocal<Student> THREAD_LOCAL_2 = new ThreadLocal<>();
private static final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(10);
private static final ThreadPoolExecutor POOL_EXECUTOR = initThreadPool(5, 10, 1000);
/** * The worker thread */
public static class WorkerThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger nextId = new AtomicInteger(1);
WorkerThreadFactory(String whatFeatureOfGroup) {
this.namePrefix = "From WorkerThreadFactory's " + whatFeatureOfGroup + "-Worker-";
}
@Override
public Thread newThread(Runnable task) {
String name = namePrefix + nextId.getAndIncrement();
return new Thread(null, task, name, 0);
}
}
/** * Initializes the thread pool */
public static ThreadPoolExecutor initThreadPool(int corePoolSize, int maxPoolSize, long keepAliveTime) {
return new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1000),
new WorkerThreadFactory("ThreadLocalDemo"),
new ThreadPoolExecutor.AbortPolicy());
}
static class Student {
int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
private static Student getStudent() {
Student s = THREAD_LOCAL_2.get();
if (null == s) {
s = new Student();
s.setAge(5);
THREAD_LOCAL_2.set(s);
}else {
s.setAge(55);
THREAD_LOCAL_2.set(s);
}
return s;
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
int finalI = i + 1;
POOL_EXECUTOR.execute(() -> {
Student student = getStudent();
System.out.println("[" + new SimpleDateFormat("HH:mm:ss.SSS").format(new Date())
+ "]--[" + Thread.currentThread().getName() + "] THREAD_LOCAL_1, threadId:" + Thread.currentThread().getId() + ", " + THREAD_LOCAL_1.get());
System.out.println("[" + new SimpleDateFormat("HH:mm:ss.SSS").format(new Date())
+ "]--[" + Thread.currentThread().getName() + "] THREAD_LOCAL_2, threadId:" + Thread.currentThread().getId() + ", " + student.getAge());
THREAD_LOCAL_1.set("THREAD_LOCAL_1 is " + finalI);
System.out.println("[" + new SimpleDateFormat("HH:mm:ss.SSS").format(new Date())
+ "]--[" + Thread.currentThread().getName() + "] THREAD_LOCAL_1, threadId:" + Thread.currentThread().getId() + ", " + THREAD_LOCAL_1.get());
THREAD_LOCAL_1.remove();
COUNT_DOWN_LATCH.countDown();
});
THREAD_LOCAL_2.remove();
}
if (COUNT_DOWN_LATCH.await(2, TimeUnit.MINUTES)) {
System.out.println("[" + new SimpleDateFormat("HH:mm:ss.SSS").format(new Date()) + "]--[" + Thread.currentThread().getName() + "] is over.");
}
POOL_EXECUTOR.shutdown();
}
}
Reference article
https://zhuanlan.zhihu.com/p/34406557
边栏推荐
- 【JUC系列】同步工具类之ThreadLocal
- Initial use of eolink
- 正大期货主账户留4行情软件用的什么?
- torch.load加载模型报错:Can‘t get attribute ‘vae_vc‘ on <module ‘__main__‘ from ‘xxxx()运行文件路径‘
- Jerry's WiFi interferes with Bluetooth [chapter]
- torch. Load load model error: can't get attribute 'VAE_ vc‘ on <module ‘__ main__‘ From 'xxxx() run file path‘
- When a technician becomes a CEO, what "bugs" should be modified?
- Pangolin编译error: ‘numeric_limits’ is not a member of ‘std’
- 力扣每日一题-第31天-1779.找到最近的有相同x或y坐标的点
- 面试突击61:说一下MySQL事务隔离级别?
猜你喜欢
![[pbootcms template] composition website / document download website source code](/img/6e/51bbb4ce961defa4abd098ff3af21f.jpg)
[pbootcms template] composition website / document download website source code

Sofaregistry source code | data synchronization module analysis

面试突击61:说一下MySQL事务隔离级别?

AUTOCAD——文字显示方式、CAD怎么直接打开天正图纸

Numpy's ndarray array Foundation

年轻就要醒着拼,年轻就要勇于尝试

&3 在浏览器中查看请求报文和响应报文

谷粒商城项目

Embedded database development programming (IV) -- DDL, DML

面试突击61:说一下MySQL事务隔离级别?
随机推荐
内插散点数据
ERP preparation of bill of materials Huaxia
Jerry's initiation of ear pairing, reconnection, and opening of discoverable and connectable cycle functions [chapter]
Gbase8s database for read only clause
联想领像 lenovoimage 部分打印机 驱动 PPD 文件
Gbase 8s extended external connection 1
GBase8s数据库INTO STANDARD 和 INTO RAW 子句
&3 在浏览器中查看请求报文和响应报文
GBase8s数据库FOR UPDATE 子句
ERP编制物料清单 基础
《自卑与超越》生活对你应有的意义
Jerry's configuration of TWS cross pairing [chapter]
Gbase8s database select has order by Clause 4
面试突击61:说一下MySQL事务隔离级别?
iMile 利用 Zadig 多云环境周部署千次,跨云跨地域持续交付全球业务
oracle 19c : change the user sys/system username pasword under Linux
LM07丨细聊期货横截面策略
&4 express框架
Gbase8s database into temp clause creates a temporary table to save query results.
论文复现——AC-FPN:Attention-guided Context Feature Pyramid Network for Object Detection.