Thoughts on Java Multithreading

Source: Internet
Author: User

Although few Java developers can ignore multi-threaded programming and the Java platform class library supports it, even fewer developers have time to study threads in depth. On the contrary, we only learn threads in a general way. If necessary, we will add new skills and technologies to our toolbox. In this way, you may build and run applications, but you can do better. Understanding the thread features of the Java compiler and JVM can help you write more efficient and better-performing Java code.
In step 5
Things Series
In this article, I will introduce some details about using Synchronization Methods, volatile variables, atomic classes, and other multi-thread programming. My discussion focuses on how these program structures interact with JVM and Java compilers, and how different interactions affect Java application performance.

1.Synchronization Method and synchronization Block
Occasionally, you will determine whether to synchronize the entire method call, or just synchronize the full sub-block of the thread in the method. In this case, it is helpful to know when the Java compiler converts source code to bytecode. It is completely different in terms of Synchronization Methods and synchronization blocks.
When the JVM executes a synchronous method, the method_info structure of the method that executes the thread identity has an acc_synchronized mark, and then it automatically obtains the object lock, calls the method, and releases the lock. If an exception occurs, the thread Automatically releases the lock.
On the other hand, synchronizing a method block bypasses JVM's built-in support for getting Object locks and Exception Handling. These functions must be explicitly written in bytecode. If you have read the bytecode that contains the synchronous block method, you will see more additional operations to manage this function. Listing 1 shows the calls generated by the synchronization method and synchronization block:

Package COM. geekcap; </P> <p> public class synchronizationexample {<br/> private int I; </P> <p> Public synchronized int synchronizedmethodget () {<br/> return I; <br/>}</P> <p> Public int synchronizedblockget () {<br/> synchronized (this) {<br/> return I; <br/>}< br/>}

The synchronizedmethodget () method generates the following bytecode:

0: aload_0
1: getfield
2: NOP
3: iconst_m1
4: ireturn

The following is the bytecode of the synchronizedblockget () method:

0: aload_0
1: DUP
2: astore_1
3: monitorenter
4: aload_0
5: getfield
6: NOP
7: iconst_m1
8: aload_1
9: monitorexit
10: ireturn
11: astore_2
12: aload_1
13: monitorexit
14: aload_2
15: athrow

 

 

 

Creating a synchronization block generates 16 lines of bytecode, but the synchronization method returns only 5 lines of code.

2. threadlocalVariable
If you want to maintain a single variable instance for all instances of a class, you will use static class member variables to achieve this. If you want to maintain an instance of a variable in each thread, you will use the thread-local variable. Threadlocal variables are different from common variables because each thread has its own variables to initialize instances. These variables can be accessed through the get () or set () methods.
Let's say that you are developing a multi-threaded code tracker to uniquely identify the path of each thread from your program. The challenge is that you need to coordinate multiple methods in multiple classes that span multiple threads. Without threadlocal, this is a very complicated problem. When a thread starts execution, it generates a unique tag for identification in the tracker and passes the unique tag to each method in the path.
With threadlocal, the problem becomes simple. The thread initializes the thread-local variable at the beginning of running, and then accesses it in each method of each class, this ensures that the variable only maintains the path information in the current execution thread. When the thread completes execution, the thread passes its specific path to a management object, which maintains all paths.
When you need to store variables based on each thread, it makes sense to use threadlocal.

3. VolatileVariable
I guess most Java developers know that the Java language contains the keyword volatile. Only about 10% of people know what it means, and only a few know how to use it efficiently. Simply put, using the volatile keyword to identify a variable means that the value of the variable will be modified by different threads. To fully understand the functions of the volatile keyword, we will first understand how the thread handles non-volatile variables.
To improve performance, the Java language specification allows JRE to maintain a copy of a reference to a variable in each thread. You can think that the "thread-local" copy of these variables is similar to the cache, which helps the thread avoid checking the main memory every time it needs to access the value of the variable.
But consider what may happen in the following scenario: both threads are started. The first thread reads the value of variable A as 5, and the second thread reads the value of variable A as 10. If variable A has changed from 5 to 10, then the first thread will not realize this change, so it will get the error value of. If the variable A is marked as volatile, and a thread reads the value of a at any time, it will query
The primary copy of A and read its current value.
If the variables in the application do not change, it makes sense to use a thread-local cache. In addition, it is helpful to know what volatile keywords can do for you.

4. VolatileCompared with synchronization
If the variable is declared as volatile, it means it will be modified by multiple threads. Naturally, you want JRE to force synchronization for volatile variables in some way. Fortunately, when accessing the volatile variable, JRE provides implicit synchronization, but it will come with a very high price: the read volatile variable is synchronized, And the write volatile variable is also synchronized, however, non-atomic operations cannot be performed.
This means that the following code is not thread-safe:

 

 

Myvolatilevar ++;

Int temp = 0; <br/> synchronize (myvolatilevar) {<br/> temp = myvolatilevar; <br/>}</P> <p> temp ++; </P> <p> synchronize (myvolatilevar) {<br/> myvolatilevar = temp; <br/>}

In other words, if a volatile variable is updated according to the above method, that is, the value is read and modified first, and then assigned a value, the result is non-thread-safe between two synchronization operations. You can consider whether to use synchronization or automatic synchronization of volatile variables based on JRE. The better way is based on your Use Case: If the value assigned to the volatile variable depends on its current value (for example, the addition operation), if you want the operation to be thread-safe, you must use synchronization.

5.Atomic field Updater
When adding or subtracting a raw data type in a multi-threaded environment, it is much better to use the atomic classes added in the Java. util. Concurrent package to write your own synchronization code block. The atomic class ensures that these operations can be performed in a thread-safe manner, such as adding or subtracting values, updating values, and adding values. The atomic classes include atomicinteger, atomicboolean, atomiclong, and atomiclong.
The challenge of using atomic classes is that all class methods, including get, set, and get-Set Method clusters are atomic. This means that the read and write operations will not modify the value of the atomic variable in synchronous mode, not just the important read-Update-write operations. If you want to have better control over the release of the synchronization code, the solution is to use the atomic field Updater.

Use atomic update
Atomic field Updater, such as atomicintegerfieldupdater, atomiclongfieldupdater, and atomicreferencefieldupdater, is the basic package class used for volatile fields. In JDK, Java class libraries use these atomic classes. But they are not widely used in applications, and you have no reason not to use them.
The example shown in Listing 2 is a class that uses atomic update to change the book someone is reading:

Package COM. geeckap. atomicexample; </P> <p> public class book <br/> {<br/> private string name; </P> <p> Public book () <br/>{< br/>}</P> <p> Public book (string name) <br/>{< br/> This. name = Name; <br/>}</P> <p> Public String getname () <br/>{< br/> return name; <br/>}</P> <p> Public void setname (string name) <br/>{< br/> This. name = Name; <br/>}< br/>}

 

The myobject class in listing 3 exposes that the whatimreading attribute is what you expect. This attribute has get and set methods, but the set method does not do the same thing. This example uses
Atomicreferencefieldupdater.

Listing 3

Package COM. geeckap. atomicexample; </P> <p> Import Java. util. concurrent. atomic. atomicreferencefieldupdater; </P> <p>/** <br/> * @ author shaines <br/> */<br/> public class myobject <br/> {<br/> private volatile book whatimreading; </P> <p> Private Static final atomicreferencefieldupdater <myobject, book> Updater = <br/> atomicreferencefieldupdater. newupdater (<br/> myobject. class, book. class, "whatimreading"); </P> <p> Public book getwhatimreading () <br/>{< br/> return whatimreading; <br/>}</P> <p> Public void setwhatimreading (Book whatimreading) <br/>{< br/> // This. whatimreading = whatimreading; <br/> Updater. compareandset (this, this. whatimreading, whatimreading); <br/>}< br/>}

Atomicreferencefieldupdater
Javadoc defines atomicreferencefieldupdater as follows:
A reflection-based tool class that can update the specified volatile reference fields of a specified class. This class is designed for atomic data structures in which multiple reference fields of the same node are updated independently.
In listing 3, newupdater can be created by calling the static method newupdater of atomicreferencefieldupdater. This method receives three parameters:
Class of the object containing this field (in this example, myobject)
Class of the object to be automatically updated
Name of the field to be automatically updated

The getwhatimreading method does not use any form of synchronization when obtaining the actual value. However, the execution of the setwhatimreading method is an atomic operation.
Listing 4 demonstrates how to use the setwhatimreading () method and how to determine the value of the variable to be modified correctly:

Package COM. geeckap. atomicexample; </P> <p> Import Org. JUnit. assert; <br/> Import Org. JUnit. before; <br/> Import Org. JUnit. test; </P> <p> public class atomicexampletest <br/> {<br/> private myobject OBJ; </P> <p> @ before <br/> Public void setup () <br/>{< br/> OBJ = new myobject (); <br/> obj. setwhatimreading (New Book ("Java 2 from scratch"); <br/>}</P> <p> @ test <br/> Public void testupdate () <br/>{< br/> obj. setwhatimreading (New Book (<br/> "Pro Java ee 5 performance management and optimization"); <br/> assert. assertequals ("Incorrect book name", <br/> "Pro Java ee 5 performance management and optimization", <br/> obj. getwhatimreading (). getname (); <br/>}</P> <p>}

View resources to learn more about atomic classes.

Conclusion
Multi-threaded programming is always challenging, but when it comes to the Java platform, it has gained support to simplify some multi-threaded programming tasks. In this article, I have discussed five things you may not know when writing multi-threaded applications based on the Java platform, including the differences between the synchronization method and the synchronization block, the threadlocal variable is used to store values for each thread, which is widely misunderstood by the volatile keyword.
(This includes the danger of dependency on volatile when synchronization is required) and the complexity of atomic classes. View resources to learn more.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.