What are the skills and usage of Java threads that are not well known?
In this article, you will see some methods and technologies that are not commonly used by the thread. Whether you are a beginner, a senior user, or a Java expert, I hope you can take a look at what you already know and what you just learned. If you think there is anything worth sharing about the thread.
Beginner
1. Thread name
Each thread in the program has a name. When a thread is created, a simple Java string is assigned to it as the thread name. The default name is "Thread-0", "Thread-1", "Thread-2", and so on. Now it's interesting to know that Thread provides two ways to set the Thread name:
The following is the simplest implementation of the thread constructor:
Class SuchThread extends Thread {
Public void run (){
System. out. println ("Hi Mom! "+ GetName ());
}
}
SuchThread wow = new SuchThread ("much-name ");
Thread name setter method:
Wow. setName ("Just another thread name ");
Yes, the thread name is variable. Therefore, we can modify its name at runtime without specifying it during initialization. The name field is actually a simple string object. That is to say, it can be as long as 2 bytes between-1 characters (Integer. MAX_VALUE ). This is enough. Note that this name is not a unique identifier, so different threads can have the same thread name. Another point is that do not use null as the thread name; otherwise, an exception will be thrown (of course, "null" is still acceptable ).
Use thread name for debugging
Since thread names can be set, it is easier to troubleshoot problems if certain naming rules are followed. A name like "Thread-6" looks too boring. It must have a better name than it. When processing user requests, you can append the transaction ID to the end of the thread name, which can significantly reduce the troubleshooting time.
"Pool-1-thread-1" #17 prio = 5 OS _prio = 31 tid = 0x00007f9d620c9800
Nid = 0x6d03 in Object. wait () [0x000000013ebcc000]
"Pool-1-thread-1", this is too serious. Let's take a look at the situation and give it a better name:
Thread. currentThread (). setName (Context + TID + Params + current Time ,...);
Now let's run jstack again, and the situation will suddenly become clear:
"Queue Processing Thread, MessageID: AB5CAD, type:
AnalyzeGraph, queue: ACTIVE_PROD, Transaction_ID: 5678956,
Start Time: 30/12/2014 17:37 "#17 prio = 5 OS _prio = 31 tid = 0x00007f9d620c9800
Nid = 0x6d03 in Object. wait () [0x000000013ebcc000]
If we can know what the thread is doing, we can get at least the transaction ID to start troubleshooting when it goes wrong. You can trace the problem, reproduce it, locate the problem, and fix it. If you want to know how to use jstack, read this article.
2. Thread priority
Another interesting attribute of a thread is its priority. The thread priority is between 1 (MINPRIORITY) and 10 (MAXPRIORITY). The default value of the main thread is 5 (NORM_PRIORITY ). Each new thread inherits the priority of the parent thread by default. Therefore, if you have not set the priority of all threads, the priority of all threads is 5. This is a property that is often ignored. We can get and modify its value through the getPriority () and setPriority () methods. This function is not available in the constructor of the thread.
Where will priority be used?
Of course, not all threads are equal. Some threads need to immediately attract CPU attention, while some threads are only background tasks. Priority is used to tell the thread scheduler of the operating system. In Takipi, this is an error tracking and troubleshooting tool developed by us. The priority of the thread responsible for handling user exceptions is MAX_PRIORITY, and the threads only report new deployment conditions, their priority is lower. You may think that a thread with a higher priority will get more time from the JVM thread scheduler. But this is true.
At the operating system level, each new thread corresponds to a local thread. The priority of the Java thread you set will be converted to the priority of the local thread, which is different on different platforms. On Linux, you can enable the "-XX: + UseThreadPriorities" option. As mentioned above, the thread priority is just a suggestion you provide. Compared with the Linux local priority, the Java thread priority cannot cover all levels (Linux has 1 to 99 priorities, and the thread priority is between-20 and 20 ). The biggest benefit is that the priority you set can be reflected in the CPU time obtained by each thread, but it is not recommended to rely entirely on the thread priority.
Advanced
3. Local Thread storage
This is slightly different from the two mentioned above. ThreadLocal is a function implemented outside the Thread class (java. lang. ThreadLocal), but it stores a unique copy of data for each Thread. As its name says, it provides local storage for the thread, that is, the variables you create are unique for each thread instance. Similar to the Thread name and Thread priority, you can customize some attributes, as if they are stored inside the Thread. Is it cool? However, don't be too happy. You have to say a few ugly words first.
There are two recommended methods to create ThreadLocal: static variables or attributes in a single instance. This can be non-static. Note that its scope is global, but it seems to be local to the thread accessing it. In the following example, ThreadLocal stores a data structure so that we can easily access it:
Public static class CriticalData
{
Public int transactionId;
Public int username;
}
Public static final ThreadLocal <CriticalData> globalData =
New ThreadLocal <CriticalData> ();
Once the ThreadLocal object is obtained, you can operate it through the globalData. set () and globalData. get () methods.
Global variable? This is not a good thing
All right. ThreadLocal can be used to store the transaction ID. It is quite useful if no exceptions are caught in the code. The best practice is to set an UncaughtExceptionHandler, which is supported by the Thread class, but you have to implement this interface by yourself. Once the UncaughtExceptionHandler is executed, there is almost no clue about what happened. Now you can get only the Thread object, and all variables that caused exceptions can no longer be accessed, because those stack frames have been popped up. Once it reaches the UncaughtExceptionHandler, this thread will have only one last breath, and the last straw that can be grasped is ThreadLocal.
Let's try this:
System. err. println ("Transaction ID" + globalData. get (). transactionId );
We can store some valuable context information related to errors to add them. ThreadLocal also has a more creative usage, that is, it is used to allocate a specific memory, so that the working thread can treat it as a cache for continuous use. Of course, it depends on how you weigh the CPU and memory. Yes, ThreadLocal should pay attention to the waste of memory space. As long as the thread is still alive, it will always exist. Unless you release it, it will not be recycled. So if you use it, you 'd better pay attention to it and keep it as simple as possible.
4. User threads and Daemon threads
Let's go back to the Thread class. Each thread in the program has a state, either a user state or a daemon state. In other words, either the foreground thread or the background thread. The main thread is a user thread by default, and each new thread inherits the thread state from the thread that created it. Therefore, if you set a thread to a daemon thread, all the threads it creates will be marked as daemon threads. If all threads in the program are daemon threads, the process will be terminated. You can use the Boolean. setDaemon (true) and. isDaemon () methods to view and set the thread status.
When will the daemon thread be used?
If the process does not end until a thread ends, the thread can be set as a daemon thread. This saves the trouble of closing threads normally and can immediately end the thread. In other words, if a thread that is executing an operation must be properly closed, otherwise there will be bad consequences, then this thread should be a user thread. Usually some key transactions, such as database input or update, cannot be interrupted.
Expert Level
5. Processor Affinity)
What we will talk about here will be closer to the hardware, that is, when the software meets the hardware. The processor affinity enables you to bind a thread or process to a specific CPU core. This means that as long as it is a specific thread, it will certainly only be executed on a specific CPU core. Generally, the thread scheduler of the operating system determines how to bind a thread based on its own logic. It is likely to take the thread priority we mentioned earlier into account.
The advantage of this is the CPU cache. If a thread only runs on a certain core, the probability of its data in the cache is greatly increased. If the data is in the CPU cache, there is no need to re-load it from the memory. The milliseconds you have saved can be used in the cutting edge. During this time, the code can be executed immediately, so that you can better use the CPU time allocated to it. Of course, there may be some Optimization at the operating system level, and the hardware architecture is of course also a very important factor, but using the processor affinity can at least reduce the chance of thread switching CPU.
As there are many factors mixed here, it is best to test the effect of the processor affinity on throughput. Maybe this method does not always significantly improve performance, but at least one advantage is that the throughput is relatively stable. The affinity policy can be refined to a very fine granularity, depending on what you want. The high-frequency trading industry is one of the best scenarios for this strategy.
Testing of processor affinity
Java has no native support for the processor's affinity. Of course, the story is not over yet. On Linux, we can use the taskset command to set the affinity of processes. Suppose we have a Java process running, and we want to bind it to a specific CPU:
Taskset-c 1 "<span style =" width: auto; height: auto; float: none; "id =" 4_nwp "> <a style =" text-decoration: none; "mpid =" 4 "target =" _ blank "href =" http://cpro.baidu.com/cpro/ui/uijs.php? C = news & cf = 1001 & ch = 0 & di = 128 & fv = 15 & jk = a4cdcab9727499ec & k = java & k0 = java & kdi0 = 0 & luki = 10 & n = 10 & p = baidu & q = 06011078_cpr & rb = 0 & rs = 1 & seller_id = 1 & sid = ec997472b9cacda4 & ssp2 = 1 & stid = 0 & t = tpclicked3_hc & tu = u1922429 & u = http % 3A % 2F % 2 Fwww % 2Eadmin10000% 2 Ecom % 2 Fdocument % 2F5854% 2 Ehtml & urlid = 0 "id =" 4_nwl "> <span style = "color: # 0000ff; font-size: 14px; width: auto; height: auto; float: none; "> java </span> </a> </span> AboutToBePinned"
If the process is already running:
Taskset-c 1 <PID>
To reach the thread level, you must add some code. Fortunately, there is an open-source library that can accomplish this function: Java-Thread-Affinity. This library is developed by Peter Lawrey of OpenHFT. The simplest and most direct way to implement this function is to use this library. Let's take an example to quickly learn how to bind a thread. For more information about this library, see its documentation on Github:
AffinityLock al = AffinityLock. acquireLock ();
In this way, you can. More advanced options for getting locks-for example, selecting a CPU based on different policies-are described in detail on Github.
Conclusion
This article introduces the five points of knowledge about threads: thread name, local Thread storage, priority, Daemon thread, and processor affinity. I hope this will open a new window for your daily work and look forward to your feedback! Can you share any other thread processing methods.