1. Sync method or sync code block?
You may occasionally wonder whether you want to synchronize this method call, or just synchronize the thread-safe subset of the method. In these cases, it is useful to know when the Java compiler will convert the source code to byte code, which handles synchronization methods and synchronized code blocks in a completely different way.
When the JVM executes a synchronization method, the thread in the execution recognizes that the METHOD_INFO structure of the method has a acc_synchronized tag setting, and then it automatically acquires the lock of the object, invokes the method, and finally releases the lock. If an exception occurs, the thread automatically releases the lock.
Synchronizing a method block, on the other hand, crosses the JVM's built-in support for acquiring object locks and exception handling, requiring explicit write capabilities in byte code. If you use the synchronization method to read the byte code of a method, you will see that there are more than 10 additional operations to manage this functionality. Listing 1 shows the calls for generating synchronization methods and synchronizing code blocks:
Listing 1. Two methods of synchronization
Package com.geekcap;
public class Synchronizationexample {
private int i;
public synchronized int Synchronizedmethodget () {return
i;
}
public int Synchronizedblockget () {
synchronized (this) {return
i;
}
}
}
The Synchronizedmethodget () method generates the following byte code:
0:aload_0
1:getfield
2:nop
3:iconst_m1
4:ireturn
Here is the byte code from 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 synchronized code block produces a 16-line byte code, and creating a synchronization method produces only 5 rows.
Back to the top of the page
2. ThreadLocal variable
Static class member variables are used if you want to maintain an instance of a variable for all instances of a class. If you want to maintain an instance of a variable in a thread, you will use a thread-local variable. The difference between a ThreadLocal variable and a regular variable is that each thread has its own initialized variable instance, which is evaluated by the get () or set () method.
Let's say you're developing a multithreaded code tracker whose goal is to uniquely identify each thread's path through your code. The challenge is that you need to reconcile multiple methods in multiple classes across multiple threads. If there is no ThreadLocal, this will be a complex problem. When a thread starts executing, it needs to generate a unique token to recognize it in the tracker, and then pass the unique token to each method in the trace.
With ThreadLocal, things get much simpler. The thread initializes the thread local variable at the start of execution, and then accesses it through each method of each class, guaranteeing that the variable will only host trace information for the currently executing thread. After execution is complete, the thread can pass its specific traces to a management object responsible for maintaining all traces.
Using ThreadLocal is useful when you need to store variable instances in threads.
3. Volatile variable
I estimate that about half of the Java developers know that the Java language contains volatile keywords. Of course, only 10% of them know exactly what it means, and there are fewer people who know how to use it effectively. In short, using the volatile keyword to identify a variable means that the value of the variable is modified by a different thread. To fully understand the role of the volatile keyword, you should first understand how a thread handles nonvolatile variables.
To improve performance, the Java language specification allows the JRE to maintain a local copy of the variable in each thread that references the variable. You can consider these "thread-local" replicas of variables to be similar to caching, helping it avoid checking primary storage each time a thread needs to access the value of a variable.
But look at what happens in the following scenario: Two threads start, the first thread reads variable A to 5, and the second thread reads variable A to 10. If variable a changes from 5 to 10, the first thread will not know about the change, so it will have the wrong value of variable a. However, if you mark variable A as volatile, then when the no pipeline reads the value of a, it will look back at the original copy of A and read the current value.
If the variables in the application do not change, then a thread-local cache comparison is OK. Otherwise, it would be helpful to know what the volatile keyword can do for you.
4. Volatile variables and synchronization
If a variable is declared as volatile, this means that it is expected to be modified by multiple threads. Of course, you would expect the JRE to exert some form of synchronization for volatile variables. Fortunately, the JRE does implicitly provide synchronization when accessing volatile variables, but there is an important reminder that the read volatile variable is synchronized, and that the write volatile variable is synchronized, but the non atomic operation is Out-of-sync.
This means that the following code is not thread-safe:
The previous statement can also be written as:
int temp = 0;
Synchronize (myvolatilevar) {
temp = Myvolatilevar;
}
temp++;
Synchronize (Myvolatilevar) {
Myvolatilevar = temp;
}
In other words, if a volatile variable is updated so that its value is read, modified, and assigned a new value at the bottom, the result will be a non thread-safe operation that is performed between two synchronous operations. You can then decide to automatically synchronize volatile variables by using synchronization or by relying on the support of the JRE. A better approach depends on your use case: if the value assigned to the volatile variable depends on the current value (for example, during an incremental operation), you must use synchronization if you want the operation to be thread-safe.
5. Atomic Field Update program
when you increment or decrement a primitive type in a multithreaded environment, it is much better to write your own synchronized code block using one of the new atomic analogies found in the Java.util.concurrent.atomic package. Atomic classes ensure that certain actions are executed in a thread-safe manner, such as incrementing and descending a value, updating a value, and adding a value. The list of atomic classes includes Atomicinteger, Atomicboolean, Atomiclong, Atomicintegerarray, and so on.
The challenge with atomic classes is that all class operations, including get, set, and a series of get-set operations are rendered in atomic states. This means that the read and write operations that do not modify the values of atomic variables are synchronized, not just important read-update-write operations. If you want more granular control over the deployment of synchronized code, the solution is to use an atomic field update.
Using Atomic Updates
Atomic field updates like Atomicintegerfieldupdater, Atomiclongfieldupdater, and Atomicreferencefieldupdater are basically wrappers that apply to volatile fields. The Java class libraries use them internally. Although they are not widely used in application code, there is no reason why they cannot be used.
Listing 2 shows an example of a class that uses atomic updates to change the bibliography that someone is reading:
Listing 2. Book Class
Package com.geeckap.atomicexample;
public class book
{
private String name;
Public book ()
{
} public book
(String name)
{
this.name = name;
}
Public String getName ()
{return
name;
}
public void SetName (String name)
{
this.name = name;
}
}
The book class is only a POJO (Java native class object) with a single field: Name.
Listing 3. MyObject class
package com.geeckap.atomicexample;
Import Java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
/** * * @author shaines/public class MyObject {private volatile book whatimreading; private static final atomicreferencefieldupdater<myobject,book> updater = Atomicreferencefieldupdater.newupdat
ER (myobject.class, book.class, "whatimreading");
Public book getwhatimreading () {return whatimreading;
} public void setwhatimreading (book whatimreading) {//this.whatimreading = whatimreading;
Updater.compareandset (This, this.whatimreading, whatimreading); }
}
As you would expect, the MyObject class in Listing 3 exposes its whatamireading properties through the get and set methods, but the set method does something different. Not only does it assign its internal book reference to the specified (which will be done using the code annotated in Listing 3), but instead uses a atomicreferencefieldupdater.
Atomicreferencefieldupdater
Atomicreferencefieldupdater's Javadoc defines it as:
An image-based utility that enables atomic updating for the specified volatile reference field of the specified class. This class is intended for use in such an atomic data structure: that is, several reference fields of the same node are independently updated with atoms.
In Listing 3, Atomicreferencefieldupdater is created by a call to its static Newupdater method, which accepts three parameters:
The class of the object that contains the field (in this case MyObject)
The class of the object that will get the atomic update (in this case, book)
The name of the field that will be updated by atomic
The real value here is that the Getwhatimreading method is executed without any form of synchronization, and the setwhatimreading is executed as an atomic operation.
Listing 4 shows how to use the Setwhatimreading () method and determine that the value changes are correct:
Listing 4. Exercise test cases for atomic updates
Package com.geeckap.atomicexample;
Import Org.junit.Assert;
Import Org.junit.Before;
Import Org.junit.Test;
public class Atomicexampletest
{
private MyObject obj;
@Before public
void SetUp ()
{
obj = new MyObject ();
Obj.setwhatimreading (new book ("Java 2 from Scratch"));
@Test public
void Testupdate ()
{obj.setwhatimreading () (New book
(
"Pro Java EE 5 Performance Management and optimization "));
Assert.assertequals ("Incorrect book name",
"Pro Java EE 5 performance Management and optimization",
Obj.getwhatimreading (). GetName ());
}
concluding remarks
multithreaded programming is always a challenge, but as the Java platform evolves, it gets the support to simplify some multithreaded programming tasks. In this article, I discussed 5 things you might not know about writing multithreaded applications on the Java platform, including the difference between synchronization methods and synchronized blocks of code, the value of using threadlocal variables for each thread store, and the widely misunderstood volatile keywords (including dependencies on Volatile to meet the risk of synchronization requirements), and a brief introduction to the complexity of atomic classes. See the Resources section for more information.