ThreadLocal
Is key null after GC?
uncertain.
(1) When using new ThreadLocal<>().set(s);
to define threadlocal, if a variable is not declared on the stack to point to it, then it is only weakly referenced. After gc, the threadlocal will be recycled. If the key is null and the value is still there, it will cause a memory leak. Therefore, be sure to call the remove method after using the threadlocal to avoid memory leaks because the key is null.
(2) When defined using ThreadLocal<object> threadLocal = new ThreadLocal<>();
the method, it is equivalent to a variable threadLocal in the stack pointing to this object, forming a strong reference. Even in the entry, as the key, it is a weak reference, but there is always a variable named "threadLocal" in the stack. There is a strong reference pointing to him, so the key will not be empty in this case. But as long as the threadLocal variable disappears after the method in which the variable is located is executed, leaving only a weak reference, the key will still be cleared and become null.
Why does key use weak reference?
If you use strong references, when ThreadLocal
the object's reference (strong reference) is recycled, ThreadLocalMap
it still holds ThreadLocal
the strong reference. If the key is not manually deleted, it ThreadLocal
will not be recycled. Therefore, as long as the current thread does not die, ThreadLocalMap
the referenced objects will not be recycled. It will not be recycled, which can be considered to cause Entry
a memory leak.
ThreadLocalMap expansion mechanism
At ThreadLocalMap.set()
the end of the method, if no data has been cleaned after performing the heuristic cleaning work, and the Entry
number in the current hash array has reached the expansion threshold of the list (len*2/3)
, the execution logic will start rehash()
: here, the detection cleaning work will be performed first , table
cleaning from the starting position backwards, table
some data may be cleaned out. At this time, it is decided whether to expand the capacity by key
judging .null
Entry
size >= threshold * 3/4
Let's take a look at the specific resize()
method. For the convenience of demonstration, the expanded tab
size is oldLen * 2
, recalculate hash
the position, and then put it into a new tab
array. If hash
a conflict occurs, look for the nearest entry
slot null
. After the traversal is completed, oldTab
all the The entry
data has been put into the new one tab
.
When used ThreadLocal
, the thread copy data created in the parent thread cannot be shared with the child thread in an asynchronous scenario.
In order to solve this problem, there is also a class in the JDK . The implementation principle is that the child thread is created InheritableThreadLocal
by calling a method in the parent thread , and the method is called in the constructor. Copy the parent thread data to the child thread in the method .new Thread()
Thread#init
Thread
init
ThreadLocal
Practical use in projects
- Store user token
- traceId link call
ThreadPoolExecutor
ThreadPoolExecutor saturation strategy definition
If the number of threads currently running simultaneously reaches the maximum number of threads and the queue is full of tasks, ThreadPoolTaskExecutor
define some strategies:
ThreadPoolExecutor.AbortPolicy
: (Default) ThrowRejectedExecutionException
to refuse processing of new tasks.ThreadPoolExecutor.CallerRunsPolicy
: Call to execute its own thread to run the task, that is,execute
run (run
) the rejected task directly in the thread that called the method. If the executor has been closed, the task will be discarded. Therefore, this strategy will reduce the speed of new task submission and affect the overall performance of the program. You can choose this strategy if your application can tolerate this delay and you require that every task request must be executed.ThreadPoolExecutor.DiscardPolicy
: New tasks are not processed and discarded directly.ThreadPoolExecutor.DiscardOldestPolicy
: This policy will discard the oldest unprocessed task request.
Two ways to create a thread pool
Method 1: ThreadPoolExecutor
Create via constructor (recommended).
Method 2: Create through Executor
the framework's tool class .Executors
FixedThreadPool
:This method returns a thread pool with a fixed number of threads. The number of threads in the thread pool always remains the same. When a new task is submitted, if there are idle threads in the thread pool, it will be executed immediately. If not, the new task will be temporarily stored in a task queue, and when a thread is idle, the task in the task queue will be processed.SingleThreadExecutor
: This method returns a thread pool with only one thread. If more than one task is submitted to the thread pool, the task will be saved in a task queue. When the thread is idle, the tasks in the queue will be executed in first-in, first-out order.CachedThreadPool
: This method returns a thread pool that can adjust the number of threads according to the actual situation. The number of threads in the thread pool is uncertain, but if there are idle threads that can be reused, the reusable threads will be used first. If all threads are working and a new task is submitted, a new thread will be created to handle the task. After all threads complete the execution of the current task, they will be returned to the thread pool for reuse.ScheduledThreadPool
: This returns a thread pool used to run tasks after a given delay or execute tasks periodically.
Method 2 is not recommended because:
FixedThreadPool
AndSingleThreadExecutor
: The use is unboundedLinkedBlockingQueue
, the maximum length of the task queue is , and a large number of requests may accumulate, resulting in OOMInteger.MAX_VALUE
.
CachedThreadPool
: A synchronization queue is usedSynchronousQueue
, which has no capacity. When there are no idle threads, threads are applied for immediately. The number of threads allowed to be created isInteger.MAX_VALUE
. A large number of threads may be created, resulting in OOM.
ScheduledThreadPool
AndSingleThreadScheduledExecutor
: The unbounded delay blocking queue usedDelayedWorkQueue
will automatically expand to 1/2 of the original capacity when the added elements are full, that is, it will never block. The maximum length of the task queue is, and aInteger.MAX_VALUE
large number of requests may accumulate, resulting in OOM.
DelayedWorkQueue
The internal elements are not sorted according to the time they are put in, but the tasks are sorted according to the length of delay. The internal data structure of "heap" is used .
Analysis of thread pool principle
Runnable vs Callable
Runnable
Interfaces don't return results or throw checked exceptions, but Callable
interfaces do.
The tool class Executors
can convert Runnable
objects into Callable
objects, which belongs to the converter pattern.
Differences between submit vs execute
execute()
The method is used to submit tasks that do not require a return value, so it is impossible to determine whether the task is successfully executed by the thread pool;
submit()
Method is used to submit tasks that require return values. The thread pool will return a FutureTask object Future
of type , and obtain the return value through the method. The method will block the current thread until the task is completed . If the method is used , if the task has not been executed within the time, it will be thrown .Future
get()
get()
get(long timeout,TimeUnit unit)
timeout
java.util.concurrent.TimeoutException
shutdown() VS shutdownNow()
shutdown()
:Close the thread pool and the status of the thread pool changes toSHUTDOWN
. The thread pool no longer accepts new tasks, but the tasks in the queue must be completed .shutdownNow()
:Close the thread pool and the status of the thread changesSTOP
. The thread pool will terminate the currently running tasks, stop processing queued tasks and return the List waiting to be executed .
isTerminated() VS isShutdown()
isShutDown
shutdown()
Returns true when the method is called .isTerminated
Whenshutdown()
the method is called and all submitted tasks are completed, it returns true
Comparison between ScheduledThreadPoolExecutor and Timer
Timer
Sensitive to changes in system clock,ScheduledThreadPoolExecutor
not;Timer
There is only one thread of execution, so long-running tasks can delay other tasks.ScheduledThreadPoolExecutor
Any number of threads can be configured.ThreadFactory
Furthermore, you can have full control over the threads created if you want (by providing ;
.ScheduledThreadPoolExecutor
Any number of threads can be configured.ThreadFactory
Furthermore, you can have full control over the threads created if you want (by providing ;TimerTask
A runtime exception thrown in will kill a thread, resulting in aTimer
panic i.e. the scheduled task will no longer run.ScheduledThreadExecutor
Not only catches runtime exceptions, but also allows you to handle them if needed (by overridingafterExecute
the methodThreadPoolExecutor
). The task that throws the exception will be canceled, but other tasks will continue to run.