Getting a singleton needs to be thread-safe, and the methods in it need to be thread-safe.
- A singleton is shared by multiple threads, so to ensure that it is thread-safe, the methods in it must be thread-safe.
- Utility classes, resource-driven classes, and singleton factory classes all need to be aware of this.
Specify meaningful thread names when creating threads or thread pools to facilitate backtracking in case of errors.
Thread resources must be provided through thread pools, and explicit creation of threads in the application is not allowed.
- The benefit of using thread pools is to reduce the time spent creating and destroying threads and the overhead of system resources, solving the problem of insufficient resources. If you don’t use thread pools, you can run out of memory or “overswitch” by creating a large number of similar threads.
Do not use Executors to create a thread pool. Use ThreadPoolExecutor to clear the running rules of the thread pool and avoid resource depletion.
-
FixedThreadPool and SingleThreadPool: The allowed request queue length is integer. MAX_VALUE, which may accumulate a large number of requests and result in OOM.
-
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.
SimpleDateFormat is a thread-unsafe class and should not be defined as static. If it is, you must lock it or use the DateUtils utility class.
- For JDK8 applications, you can use Instant instead of Date, LocalDateTime instead of Calendar, and DateTimeFormatter instead of Simpledateformatter.
In high concurrency, synchronous calls should consider the performance cost of locking. If you can use lock-free data structures, don’t use locks; If you can lock blocks, don’t lock the whole method body. If you can use object locks, don’t use class locks.
When multiple resources, database tables, and objects are locked at the same time, ensure that the lock sequence is consistent; otherwise, deadlocks may occur.
- Thread 1 must lock tables A, B, and C in sequence before updating. Thread 2 must lock tables A, B, and C in sequence; otherwise, deadlock may occur.
When modifying the same record concurrently, you need to lock it to avoid update loss. Either the application layer locks, the cache locks, or the database layer optimistic locks, using Version as the basis for updates.
- If the probability of each access conflict is less than 20%, optimistic lock is recommended; otherwise, pessimistic lock is recommended. The number of optimistic lock retries must be at least three.
When multiple threads process timed tasks in parallel, when a Timer runs multiple TimerTasks, other tasks will automatically terminate as long as one of them does not catch the exception thrown. ScheduledExecutorService does not have this problem.
CountDownLatch is used for asynchronous to synchronous operations. Each thread must call the countDown method before exiting. The thread executes the code to watch for a catch exception and ensure that the countDown method can execute to avoid the main thread failing to execute to the await method. The result is not returned until timeout.
- Please try… A finally statement executes the countDown method, similar to closing a resource.
Avoid Random instances being used by multiple threads because sharing the instance, while thread-safe, can degrade performance due to competing for the same seed.
- Random instances include instances of java.util.random or math.random ().
- After JDK7, API ThreadLocalRandom can be used directly.
- Before JDK7, you could put Random in a ThreadLocal and use it only in the local thread.
Double-checked locking is used to optimize delayed initialization, as long as it is not a particularly old JDK version (under 1.4), double-checked locking is fine.
Volatile solves the problem of multithreaded memory not being visible. Multiple reads on one write can solve variable synchronization problems, but multiple writes cannot solve thread safety problems.
- If the count++ operation is implemented using the following class:
- AtomicInteger count = new AtomicInteger();
- count.addAndGet(1);
- If it is JDK8, the LongAdder object is recommended for better performance than AtomicLong (reducing the number of optimistic lock retries).
When the capacity of HashMap is insufficient for resize, dead links may occur due to high concurrency, resulting in CPU surge. Avoid this risk during development.
- When developing the program, estimate the amount of usage and set the initial value based on the amount of usage.
ThreadLocal does not solve the problem of updating shared objects. Static decoration is recommended for ThreadLocal objects. This variable is common to all operations within a thread, so it is set to static. All instances of this class share this static variable, which means that the class is loaded when it is first used, only one piece of storage is allocated, and all objects of this class (as long as they are defined within this thread) can manipulate this variable.