What are some of the less known tricks and usages of Java threads?
Turnip cabbage each their own. Like I like Java. Learning, which is one of the reasons I like it. The tools you use in your daily work often have things you never know about, such as a method or some interesting usage. such as threading. Yes, it's a thread. Or, specifically, the thread class. When we build high-scalability systems, we often face a variety of concurrent programming problems, but what we have to say now may be slightly different.
From this article you will see some of the less common methods and techniques provided by the thread. Whether you're a beginner or an advanced user or a Java expert, hopefully you'll see what you already know and what you just know. If you think there is anything else worth sharing about threads, hopefully we can respond to them in a positive response below. Well, let's start with the first.
Beginner 1. Thread Name
Each thread in the program has a name, and a simple Java string is assigned to it as the thread name when the thread is created. The default name is "Thread-0″," "Thread-1″," Thread-2″ and so on. Now, here's the funny thing.--thread provides two ways to set the name of a thread:
- Thread constructors, here is the simplest implementation:
123456789 |
class suchthread extends thread {      public void run () { system.out.println ( "Hi mom!" + GetName ());      } } Suchthread wow = new suchthread ( "Much-name" ); |
- Thread Name Setter Method:
1 |
wow.setName(“Just another thread name”); |
Yes, the thread name is mutable. So we can modify its name at run time without having to specify it at the time of initialization. The Name field is actually a simple string object. That means it can reach 2³¹-1 characters that long (integer.max_value). It's enough. Note that this name is not a unique identity, so different threads can also have the same thread name. Also, do not use NULL as the thread name, otherwise an exception will be thrown (of course, "null" is OK).
To debug a problem by using the thread name
Now that you can set the name of a thread, if you follow a certain naming convention, it can be easier to troubleshoot when something is wrong. "Thread-6″ such a name looks too heartless, there must be a better name than it." When processing a user request, you can append the transaction ID to the thread name, which can significantly reduce the time you are troubleshooting the problem.
12 |
“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 look at what this is and give it a good name:
1 |
Thread.currentThread().setName(Context + TID + Params + current Time, ...); |
Now that we are running the Jstack, the situation will be enlightened:
1234 |
”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, then at least we can get the transaction ID to start troubleshooting when it goes wrong. You can retrace the problem, reproduce it, then position the problem and fix it. If you want to know what jstack to use, you can read this article.
2. Thread Priority
The thread also has an interesting property that is its priority. The thread has a priority of between 1 (minpriority) and maxpriority, and the main path defaults to 5 (norm_priority). Each new thread inherits the priority of the parent thread by default, so if you have not set it, all threads have a priority of 5. This is a commonly overlooked attribute, and we can get and modify its value through the getpriority () and SetPriority () methods. There is no such function in the constructor of the thread.
Where will the priority be used?
Of course, not all threads are equal, and some threads need immediate attention from the CPU, while others are just background tasks. The priority is the thread scheduler that is used to tell these to the operating system. In Takipi, this is an error tracking and troubleshooting tool we developed, the thread that handles the user exception is the priority of max_priority, and those that are simply reporting the new deployment situation will have a lower priority. You might think that a higher-priority thread would get more time from the JVM's thread scheduler. But in fact and all this.
At the operating system level, each new thread will correspond to a local thread, and the priority of the Java thread you set will be converted to the priority of the local thread, which is different on each platform. On Linux, you can turn on the "-xx:+usethreadpriorities" option to enable this feature. As mentioned earlier, the thread priority is just a recommendation that you provide. The priority of Java threads does not override all levels compared to Linux local priorities (Linux has 1 to 99 priorities, and threads have a priority of 20 to 20). The biggest benefit is that the priority you set can be reflected in the CPU time that each thread gets, but it is not recommended to rely entirely on thread precedence.
Advanced Article 3. Thread-Local Storage
This is slightly different from the two mentioned earlier. ThreadLocal is a feature implemented outside the thread class (java.lang.ThreadLocal), but it stores a unique piece of data for each thread. As its name implies, it provides local storage for threads, meaning that the variables you create are unique to each thread instance. Like thread names and thread priorities, you can customize some properties as if they were stored inside thread threads, do they feel cool? But don't be too early to be happy, there are a few ugly words to say before the first.
There are two recommended ways to create threadlocal: either a static variable or a property in a singleton instance, which can be non-static. Note that its scope is global, but it seems to be local to the thread that accesses it. In the following example, Threadlocal stores a data structure so that we can easily access it:
12345678 |
public static class criticaldata { &NBSP;&NBSP;&NBSP;&NBSP; public int transactionid; &NBSP;&NBSP;&NBSP;&NBSP; public int username; } public Static final threadlocal<criticaldata> GlobalData = &NBSP;&NBSP;&NBSP;&NBSP; new threadlocal<criticaldata> (); |
Once the Threadlocal object is acquired, it can be manipulated by the Globaldata.set () and Globaldata.get () methods.
Global variables? It's not a good thing.
also altogether. Threadlocal can be used to store transaction IDs. It is useful if there is an uncaught exception in your code. The best practice is to set up a uncaughtexceptionhandler, which is supported by the thread class itself, but you have to implement this interface yourself. Once executed in the Uncaughtexceptionhandler, there was little clue as to what was going on. All you can get now is the thread object, which is no longer accessible to all the variables that caused the exception, because those stack frames have been ejected. Once in the Uncaughtexceptionhandler, the thread is left with a final breath, and the only last straw to catch is threadlocal.
Let's try this out:
1 |
System.err.println( "Transaction ID " + globalData.get().transactionId); |
We can add some valuable contextual information related to the error to the inside of the store. Threadlocal also has a more creative usage, which is to use it to allocate a specific piece of memory so that the worker thread can use it as a cache. Of course, there's no use to see how you weigh the CPU and memory. Yes, the threadlocal need to be aware of is that it will cause a waste of memory space. As long as the thread is alive, it will always exist, and it will not be recycled unless you voluntarily release it. So if you use it, you'd better pay attention and try to keep it simple.
4. User Threads and Daemon threads
Let's go back to the thread class. Each thread in the program will have 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 the user thread by default, and each new thread inherits the thread state from the thread that created it. So if you set a thread to be a daemon thread, all the threads it creates are flagged as daemons. If all the threads in the program are daemons, then the process terminates. We can view and set the thread state through the Boolean Setdaemon (True) and. Isdaemon () methods.
When will the daemon thread be used?
If a process does not have to wait until a thread ends to terminate, the thread can be set as a daemon thread. This eliminates the hassle of gracefully shutting down threads and immediately ends the thread. In other words, if a thread that is performing an operation has to be shut down correctly or there will be bad consequences, then the thread should be the user thread. These are often critical transactions, such as database entries or updates, that are not interrupted.
Expert level 5. Processor Affinity (Processor Affinity)
This will be closer to the hardware, that is, when the software meets the hardware. Processor affinity allows you to bind a thread or process to a specific CPU core. This means that as long as it is a particular thread, it must be executed only on a specific CPU core. In general, how bindings are determined by the operating system's thread scheduler is based on its own logic, and it is likely to take into account the thread priorities we mentioned earlier.
The benefit of doing this is CPU caching. If a thread only runs on a core, the probability of its data being in the cache is greatly increased. If the data is exactly in the CPU cache, then there is no need to re-download it from memory. The milliseconds you save can be used on the edge of the blade, where the code can start executing immediately and make better use of the CPU time allocated to it. Of course, there may be some optimizations at the operating system level, and the hardware architecture is certainly an important factor, but leveraging the affinity of the processor can at least reduce the chance of threads switching CPUs.
Because of the many factors that are mixed here, how much processor affinity affects throughput, it is best to prove it in a test way. Perhaps this method does not always significantly improve performance, but at least one benefit is that throughput is relatively stable. Affinity strategies can be refined to very granular granularity, depending on what you specifically want. The high-frequency trading industry is one of the most capable scenarios of this strategy.
Processor Affinity Testing
Java has no native support for processor affinity, and of course, the story hasn't ended yet. On Linux, we can use the Taskset command to set the affinity of the process. Suppose we now have a Java process running, and we want to bind it to a specific CPU:
1 |
taskset -c
1 “<span id=
"3_nwp" style=
"width: auto; height: auto; float: none;"
><a id=
"3_nwl" href=
"http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=fa4534942133bd2f&k=java&k0=java&kdi0=0&luki=10&n=10&p=baidu&q=06011078_cpr&rb=0&rs=1&seller_id=1&sid=2fbd3321943445fa&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000%2Ecom%2Fdocument%2F5854%2Ehtml&urlid=0" target=
"_blank" mpid=
"3" style=
"text-decoration: none;"
><span style=
"color:#0000ff;font-size:14px;width:auto;height:auto;float:none;"
>java</span></a></span> AboutToBePinned”
|
If it is a process that is already running:
You'll need to add some code to get to the thread level. Fortunately, there is an open source library that can do this: java-thread-affinity. The library was developed by Peter Lawrey of OPENHFT, and the simplest and most straightforward way to do this is to use the library. Let's take a quick look at how to bind a thread with an example, and refer to its documentation on GitHub for more details about the library:
1 |
AffinityLock al = AffinityLock.acquireLock(); |
That's all you can do. Some of the more advanced options for acquiring locks--such as choosing cpu--based on different strategies--are described in detail on GitHub.
Conclusion
In this article we introduce 5 points of knowledge about threads: Thread name, thread local storage, priority, daemon thread, and processor affinity. I hope this will open up a new window for the content you use in your daily work, and look forward to your feedback! Is there anything else we can share with you about threading, please enlighten me.
5 tips for using Java threads