Synchronized synchronization block and volatile synchronization variable, synchronized lock variable
The Java language includes two internal synchronization mechanisms: Synchronous block (or method) and volatile variables. Both mechanisms are proposed to achieve code thread security. Among them, the synchronization of Volatile variables is poor (but sometimes it is simpler and has lower overhead), and its usage is more error-prone.
Synchronized synchronization Block
Synchronization blocks in Java are marked with synchronized. The synchronization block is synchronized to an object in Java. All synchronization blocks synchronized to an object can only be entered and operated by one thread at the same time. All other threads waiting to enter the synchronization block will be blocked until the threads executing the synchronization block exit.
There are four different synchronization blocks:
Instance method: one instance and one thread.
Static Method: A class can only be executed by one thread at the same time.
Synchronization block in the instance method
Synchronization block in Static Method
This is the best option for multithreading:
public class MyClass { public static void log2(String msg1, String msg2){ synchronized(MyClass.class){ log.writeln(msg1); log.writeln(msg2); } }}
The above synchronization blocks are synchronized to different objects. The actual synchronization block depends on the actual situation.
Instance method Synchronization
The following is a synchronous instance method:
public synchronized void add(int value){ this.count += value;}
Note the synchronized keyword in the method declaration. This tells Java that the method is synchronous.
Java instance method synchronization is synchronized to the object that owns the method. In this way, the methods of each instance are synchronized to different objects, that is, the instance to which the method belongs. Only one thread can run in the instance method synchronization block. If multiple instances exist, one thread can perform operations in one instance synchronization block at a time. One instance and one thread.
Static Method Synchronization
Static Method synchronization also uses the synchronized keyword like the instance method synchronization method. Java static method synchronization is as follows:
public static synchronized void add(int value){ count += value;}
Similarly, the synchronized keyword tells Java that the method is synchronous.
Static Method synchronization is performed on the class object where the method is located. Because a class in a Java Virtual Machine can only correspond to one class object, only one thread is allowed to execute static Synchronization Methods in the same class at the same time.
For static Synchronization Methods in different classes, a thread can execute static Synchronization Methods in each class without waiting. Regardless of the static synchronization method in the class, a class can only be executed by one thread at the same time.
Synchronization block in the instance method
Sometimes you do not need to synchronize the entire method, but a part of the synchronization method. Java can synchronize some of the methods.
An example of a synchronization block in a non-synchronous Java method is as follows:
public void add(int value){ synchronized(this){ this.count += value; } }
In this example, the Java synchronization block constructor is used to mark that a piece of code is synchronized. The code is executed in the same way as the synchronization method.
Note that the Java synchronization block constructor enclose objects with parentheses. In the preceding example, "this" is used to call the instance itself of the add method. The object enclosed in parentheses in the synchronization constructor is called the monitor object. The above Code uses the monitor Object synchronization, and synchronizes the instance method using the instance that calls the method itself as the monitor object.
Only one thread can be executed in the Java method synchronized to the same monitor object at a time.
The following two examples synchronize the instance objects they call, so they are equivalent in the synchronous execution effect.
public class MyClass { public synchronized void log1(String msg1, String msg2){ log.writeln(msg1); log.writeln(msg2); } public void log2(String msg1, String msg2){ synchronized(this){ log.writeln(msg1); log.writeln(msg2); } } }
In the preceding example, only one thread can be executed in any of the two synchronization blocks.
If the second synchronization block is not synchronized to this instance object, the two methods can be executed simultaneously by the thread.
Synchronization block in Static Method
Similar to the above, the following is an example of two static methods for synchronization. These methods are synchronized to the class object to which the method belongs.
public class MyClass { public static synchronized void log1(String msg1, String msg2){ log.writeln(msg1); log.writeln(msg2); } public static void log2(String msg1, String msg2){ synchronized(MyClass.class){ log.writeln(msg1); log.writeln(msg2); } } }
These two methods cannot be simultaneously accessed by threads.
If the second synchronization block is not synchronized to the object MyClass. class. The two methods can be simultaneously accessed by the thread.
Java synchronization instance
In the following example, two threads are started and the add method of the same instance of the Counter class is called. Because the method is synchronized to the instance to which the method belongs, only one thread can access the method at the same time.
public class Counter{ long count = 0; public synchronized void add(long value){ this.count += value; } } public class CounterThread extends Thread{ protected Counter counter = null; public CounterThread(Counter counter){ this.counter = counter; } public void run() { for(int i=0; i<10; i++){ counter.add(i); } } } public class Example { public static void main(String[] args){ Counter counter = new Counter(); Thread threadA = new CounterThread(counter); Thread threadB = new CounterThread(counter); threadA.start(); threadB.start(); } }
Two threads are created. Their constructor references the same Counter instance. The Counter. add method is synchronized to the instance because the add method is an instance method and is marked with the synchronized keyword. Therefore, only one thread can call this method at a time. The other thread must wait until the first thread exits the add () method before continuing to execute the method.
If two threads reference two different Counter instances, they can call the add () method at the same time. These methods call different objects, so these methods are synchronized to different objects. These method calls will not be blocked. As shown in the following example:
public class Example { public static void main(String[] args){ Counter counterA = new Counter(); Counter counterB = new Counter(); Thread threadA = new CounterThread(counterA); Thread threadB = new CounterThread(counterB); threadA.start(); threadB.start(); } }
Note that the two threads, threadA and threadB, no longer reference the same counter instance. The add methods of councounter and counterB are synchronized to the objects to which they belong. Calling the counterB add method does not block calling the counterB add method.
Volatile synchronization variable
To improve the efficiency, the thread copies A member variable (such as A) (such as B), and the access to A in the thread is actually B. Only A and B are synchronized in some actions. Therefore, A and B are inconsistent. Volatile is used to avoid this situation. Volatile tells jvm that the modified variables do not keep copies and directly access the primary memory (that is, A mentioned above ).
A good way to understand the volatile feature is to use the same monitor lock to synchronize a single read/write operation on the volatile variable. The following is an example.
Class VolatileFeaturesExample {volatile long vl = 0L; // use volatile to declare a 64-bit long variable public void set (long l) {vl = l; // write of a single volatile variable} public void getAndIncrement () {vl ++; // composite (multiple) read/write of volatile variable} public long get () {return vl; // read a single volatile variable }}
Assume that multiple threads call the three methods of the above program respectively. This program is equivalent to the following program in semantics:
Class VolatileFeaturesExample {long vl = 0L; // 64-bit long common variable public synchronized void set (long l) {// use the same monitor to synchronize the write of a single common variable vl = l;} public void getAndIncrement () {// call the long temp = get () Common method (); // call the synchronized read method temp + = 1L; // set (temp); // call the synchronized write method} public synchronized long get () {// use the same monitor to synchronize return vl for reading a single common variable ;}}
As shown in the preceding example, a single read/write operation on a volatile variable is synchronized with the read/write operation on a common variable using the same monitor lock, they have the same execution effect.
The happens-before rule of the monitor lock ensures the memory visibility between the monitor release and the two threads that obtain the monitor. This means that the read of a volatile variable is always visible (any thread) write the final content of the volatile variable.
The semantics of the monitor lock determines the atomicity of code execution in the critical section. This means that even 64-bit long and double variables, as long as they are volatile variables, the read and write operations on the variables will be atomic. For multiple volatile operations or compound operations similar to volatile ++, these operations are not atomic in general.
In short, the volatile variable has the following features:
Visibility. The read of a volatile variable always shows (any thread) The Final write to this volatile variable. Atomicity: read/write operations on any single volatile variable are atomic, but composite operations similar to volatile ++ are not atomic.
References:
Java Theory and Practice: Correct Use of Volatile Variables