1. Basic definitions

1.1 synchronized

Synchronized can act on a piece of code or method to ensure both visibility and atomicity. Visibility: Synchronized or Lock ensures that only one thread acquires the Lock at a time, and changes to variables are flushed to main memory before the Lock is released.

Atomicity: Once an operation is started, it cannot be disturbed by other threads. To put it crudely, you either don’t do it, or you do it all.

1.2 volatile

Volatile is the variable modifier and is visible. The basic definition of visibility is that if a thread modiates a variable that is volatile, the value is immediately updated to main memory and can be retrieved as soon as another thread needs to read it.

Essence: To speed up Java operations on variables are usually performed on the thread’s register or CPU cache before being synchronized to main memory, whereas volatile variables are read and written directly to main memory.

Back to the source: The execution of volatile involves an important CPU concept: instruction rearrangement

Instruction reordering: Instruction reordering means that during program execution, the compiler and CPU may reorder instructions for performance reasons. Even if the order of instruction execution is not necessarily the same as the physical order, it ensures that the final result of program execution is the same as the result of code sequential execution. If only sychronized and volatile were used to ensure atomicity, order, and visibility during program execution, the code would become extremely cumbersome. The JMM provides happening-before rules to constrain whether contention exists between data and whether the thread environment is safe, based on semantics (e.g., variable names are defined in order, written statements are executed Before read statements, etc.)

When a program performs a read or write to a volatile variable, it ensures that the preceding operation is complete and that the result is visible to the following operation, but that the following operation has not been performed.

1.3 summarize

(1) Write once, read and write everywhere. One thread is responsible for updating variables, while the other reads variables (but does not update them) and performs logic based on their new values. (2) Volatile is visible but does not guarantee atomicity. (3) In terms of performance, synchronized is inefficient, and volatile usually performs better than synchronized.

In some places, volatile is no substitute for synchronized because it does not guarantee atomicity.

2 Basic Usage

Use only synchronized, not volatile

public class TestSync { public volatile int inc = 0; public synchronized void increase() { inc++; } public static void main(String[] args) { final TestSync test = new TestSync(); for(int i=0; i<10; i++){ new Thread(){ public void run() { for(int j=0; j<1000; j++) test.increase(); }; }.start(); } while(thread.activecount ()>1) thread.yield (); System.out.println(test.inc); }}Copy the code

Augmentation is not atomic, and volatile does not guarantee atomicity. Suppose I = 0, A, B both execute the I ++ instruction. A reads I = 0; Switch to B and start reading I = 0; Cut back to A and execute I ++, where I = 1; I cut to B, because B already read I = 0, and I ++, I = 1. The same goes for Inc, which often conflicts, resulting in a final value < 10000. Increase and synchronized solve this problem.

// thread 1: context = initContext(); // Statement 1 Context initialization inited = true; Statement 2 // Thread 2: while(! inited ){ context.dosomethinh() sleep() }Copy the code

Because the instructions are reordered, it is possible that statement 2 will execute before statement 1, possibly causing the context to be uninitialized, and thread 2 will use the uninitialized context to operate on it, causing the program to fail.

This problem does not occur if the inited variable is modified with the volatile keyword.

3 synchronized advanced usage

What is the difference between using synchronized to modify static and non-static methods? Synchronized modifies a nonstatic method: Locks the object on which the method is invoked.

A: The result of accessing two synchronous methods of the same object in two threads is: mutual exclusion is generated. Colloquially, it is similar to a house with many rooms but only one key.

B: The result of calling the same synchronous method for different objects in two threads: no mutex is generated. In layman’s terms, it’s like two houses, two keys

Synchronized refers to a static method that locks a class object (.class).

A: Using A class object to call two different synchronized methods directly from two threads results in mutual exclusion

B: Calling static or non-static methods from two threads with a static object of the same class results in mutual exclusion.

C: An object calling a statically synchronized method and a nonstatically synchronized method in two threads results in no mutex. (Class and object)