Concurrent processing


1. [Mandatory] Obtaining a singleton object must ensure thread safety, and the methods must also ensure thread safety.

Note: Resource-driven classes, tool classes, and singleton factory classes all require attention.

2. [Mandatory] Please specify a meaningful thread name when creating a thread or thread pool to facilitate backtracking when an error occurs.

Positive example:

public class TimerTaskThread extends Thread {
public TimerTaskThread(){
super.setName("TimerTaskThread"); ...
}

3. [Mandatory] Thread resources must be provided through the thread pool, and explicit creation of threads in the application is not allowed.

Note: The advantage of using a thread pool is to reduce the time spent on creating and destroying threads and the overhead of system resources, and solve the problem of insufficient resources. If the thread pool is not used, it may cause the system to create a large number of similar threads, leading to memory consumption or "excessive switching" problems.


4. [Mandatory] Thread pools are not allowed to be created using Executors, but through ThreadPoolExecutor. This

processing method allows students to write Make the operating rules of the thread pool clearer and avoid the risk of resource exhaustion.

Description: The disadvantages of the thread pool object returned by Executors are as follows:

1)

FixedThreadPool and SingleThreadPool :

The allowed request queue length is Integer.MAX_VALUE, which may accumulate a large number of requests, resulting in OOM.

2)

CachedThreadPool and ScheduledThreadPool:

The number of threads allowed to be created is Integer.MAX_VALUE, which may create a large number of threads, resulting in OOM .


5. [Mandatory] SimpleDateFormat is a thread-unsafe class. Generally, it should not be defined as a static variable. If it is defined as

static, it must be locked or use DateUtils Tools.

Positive example: Pay attention to thread safety and use DateUtils. The following processing is also recommended:

private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
@ Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};

Note: If it is a JDK 8 application, you can use Instant instead of Date, LocalDateTime instead of Calendar, DateTimeFormatter instead of Simpledateformatter, the official explanation: simple beautiful strongimmutable thread - safe.


#6. [Mandatory] When concurrency is high, synchronous calls should consider the performance loss of locks. If you can use lock-free data structures, don't use locks; if you can

lock blocks, don't lock the entire method body; if you can use object locks, don't use class locks.


7. [Mandatory] When locking multiple resources, database tables, and objects at the same time, you need to maintain a consistent locking order, otherwise may cause a deadlock.

Note: Thread one needs to lock all tables A, B, and C in order before it can perform the update operation. Then the locking sequence of thread two must also be It is A, B, C, otherwise a deadlock may occur.


#8. [Mandatory] When modifying the same record concurrently, to avoid losing updates, either lock it at the application layer, lock it in the cache, or The database layer uses optimistic locking and uses version as the update basis.

Note: If the probability of conflict per access is less than 20%, it is recommended to use optimistic locking, otherwise use pessimistic locking. The number of retries

for optimistic locking must not be less than 3 times.


9. [Mandatory] When multi-threads process scheduled tasks in parallel, when Timer runs multiple TimeTasks, as long as one of them does not catch the exception thrown by , the other The task will automatically terminate. Using ScheduledExecutorService does not have this problem.


10. [Recommended] Use CountDownLatch to perform asynchronous to synchronous operation. Each thread must call the countDown

method before exiting, and the thread executes the code Pay attention to the catch exception and ensure that the countDown method can be executed to prevent the main thread from being unable to execute the countDown method and the result will not be returned until timeout.

Note:

Note that the exception stack thrown by the child thread cannot be reached by try - catch in the main thread.


11. [Recommendation] Avoid Random instances being used by multiple threads. Although sharing this instance is thread-safe, it will cause performance degradation due to competition for the same

seed. .

Description:

Random instances include java . util . Random instances or Math . random() instances.

Positive example:

After JDK 7, you can use API ThreadLocalRandom directly. Before JDK 7, you can achieve one instance for each thread.

##12. [Recommendation] Use double-checked locking (in concurrent scenarios) to optimize the hidden problems of delayed initialization (please refer to The " Double - Checked Locking is Broken " Declaration), one of the simpler solutions to the recommended problem

(applicable to JDK 5 and above), declare the target attribute as volatile.

Counterexample:

class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null) synchronized(this) {
if (helper == null)
helper = new Helper();
}
return helper;
}
// other functions and members...
}

13. [Reference] volatile solves the problem of invisible memory in multi-threads. For one write and multiple reads, the variable synchronization problem can be solved, but if there are multiple writes, the thread safety problem cannot be solved. If it is a count operation, use the following class to implement it: AtomicInteger count = new AtomicInteger(); count . addAndGet( 1 ); If it is JDK 8, it is recommended to use the LongAdder object, which is better than AtomicLong Better performance (reduces the number of retries for optimistic locking).


14. [Reference] When HashMap has insufficient capacity for resize, dead links may occur due to high concurrency, causing the CPU to soar. Developed in

Pay attention to avoid this risk during the process.


15. [Reference] ThreadLocal cannot solve the update problem of shared objects. It is recommended that ThreadLocal objects be decorated with static

. This variable is common to all operations within a thread, so it is set as a static variable. All such instances share this static variable, which means that it is loaded when the class is used for the first time and only a piece of storage is allocated. Space, all such objects (only

if defined within this thread) can manipulate this variable.