Objective
Communication between threads is primarily caused by the sharing of references to field access and object reference fields, which can result in two types of errors, thread interference, and memory consistency errors. Java synchronization is a way to prevent these errors, but when multiple threads access the same resource it causes the thread to perform slowly and even suspends execution.
Threading interference (thread interference)
Example
class Counter { privateint c = 0; Public void increment () { C++ ; } Public void Decrement () { C--; } Public int value () { return C; }}
View Code
If there are now two threads, thread a executes increment, thread B executes decrement, and they all use the same variable C, which can cause interference. Even if you execute very simple statements, simple statements can be translated into multiple steps of a Java virtual machine, such as C + +, which can be decomposed into three steps:
1. Retrieves the current value of C.
2, the search value plus 1.
3. Store the value back in C.
Ps:c-can also be decomposed into the same steps, but the second step is minus 1.
If thread A and thread B are called almost at the same time, and the initial value of C is 0, then the steps they interleave may be in the following order:
Thread A: retrieves C. Thread B: Retrieves C. Thread A: Increase the retrieval value; The result is 1. Thread B: reduce the retrieved value; The result is -1. Thread A: Store the result in C; C is now 1. Thread B: Store the result in C; C is now -1.
The result of thread A is missing and is covered by thread B. This interleaving is only a possibility, or the result of B may be lost, or it may not go wrong. Because the order is unpredictable, errors in thread interference can be difficult to spot and fix.
Memory consistency Error
Different threads see the same piece of data in memory but have different "views", for a complex reason, as programmers most need to do is to deal with the "happens-before" relationship, to avoid problems.
Synchronization method
Java provides two basic synchronization methods: The synchronous method and the synchronization statement. The behavior of synchronization is built on the basis of locks, each object has a fixed lock associated with it, and the thread that wants to access the object must first acquire the object's lock (not the blocking thread), release the lock when it finishes, and establish a happens-before relationship with the thread that requested the same lock.
The role of the synchronization method:
1. When a thread is executing a synchronization method for an object, all other threads that call the object's synchronization method will be blocked until the first thread finishes executing.
2, when a synchronous method exits, it automatically establishes a happens-before relationship with subsequent calls to the synchronization method (the same object), ensuring that all threads are visible to the modification of the object's state.
Attention:
1. Using the Synchronized keyword in a constructor is a syntax error. The synchronization constructor is meaningless because only the thread that created the object can access it at build time.
2. If an object is visible to more than one thread, all read or write operations to that object variable are completed by the synchronous method, or there will be thread interference and memory consistency errors.
Public classSynchronizedcounter {Private intc = 0; Public synchronized voidIncrement () {c++; } Public synchronized voidDecrement () {C--; } Public synchronized intvalue () {returnC; }}View Code
Synchronization statements
Another way to create synchronous code, unlike synchronous methods, is to specify an object that provides an internal lock. Synchronous statements are useful for improving concurrency through fine-grained synchronization.
For example, suppose the class Mslunch has two instance fields C1 and C2, which are never used together ( very important prerequisites!). ). All updates to these fields must be synchronized, but there is no reason to prevent C1 updates from interleaving with the C2 update, which creates unnecessary blocking to reduce concurrency. Instead of using a synchronous method, we create two objects to provide locks.
Public classMslunch {Private LongC1 = 0; Private LongC2 = 0; PrivateObject Lock1 =NewObject (); PrivateObject Lock2 =NewObject (); Public voidinc1 () {synchronized(LOCK1) {C1++; } } Public voidInc2 () {synchronized(lock2) {C2++; } }}View Code
volatile keyword
Atomic manipulation: An atomic operation that either occurs or does not occur. such as c=0; (Not long and double types) This operation is performed and will occur. Another example: C + +, can be divided into three operation steps, execution may lose some steps, it is not an atomic operation. There is a thread-safety problem with non-atomic operations, and synchronous methods and synchronous statements can turn it into an atomic operation.
A volatile variable is a slightly weaker synchronization mechanism, with all variables declared as volatile (including long and double), and both reads and writes are atomic.
Volatile variable Characteristics:
1. When a thread reads a volatile variable, it sees always the most recent value.
2, atomic action can not be staggered, use volatile variables without worrying about thread interference.
Some atomic classes are provided under the PS:java.util.concurrent package.
Reference documents
Https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
Java Synchronization (synchronization)