The synchronized keyword represents that this method is locked. It is equivalent to no matter which thread (such as thread A), when running this method, you must check whether other threads B (or C, D, etc.) are using this method (or other synchronization methods of this class). If so, wait for thread B (or C, D) that is using the synchronized method to run this method before running this method. If not, lock the caller and run it directly. It includes two usages: the synchronized method and the synchronized block.
The multi-threaded synchronization mechanism locks resources so that at the same time, only one thread can operate, and synchronization is used to solve the problems that may arise when multiple threads access simultaneously.
The synchronization mechanism can be implemented using the synchronized keyword.
When the synchronized keyword modifies a method, the method is called the synchronization method.
When the synchronized method is executed or an exception occurs, the lock will be automatically released.
The following is an example to analyze the usage of synchronized keywords.
1.Differential use of synchronized keywords
Example Program 1
public class ThreadTest { public static void main(String[] args) { Example example = new Example(); Thread t1 = new Thread1(example); Thread t2 = new Thread1(example); t1.start(); t2.start(); } } class Example { public synchronized void execute() { for (int i = 0; i < 10; ++i) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Hello: " + i); } } } class Thread1 extends Thread { private Example example; public Thread1(Example example) { this.example = example; } @Override public void run() { example.execute(); } } Whether to prepend the synchronized keyword in execute() method, the execution results of this example program will be very different.
If the synchronized keyword is not added, the two threads execute the execute() method at the same time, and the output is two groups of concurrent.
If the synchronized keyword is added, a set of 0 to 9 will be output first, and then the next set will be output, indicating that the two threads are executed in sequence.
2. Multi-threading situation of multiple methods
Change the program and add another method execute2() to the Example class.
Then write a thread class Thread2. The run() method in Thread2 executes execute2(). Both methods in the Example class are modified by the synchronized keyword.
Example Program 2
public class ThreadTest{ public static void main(String[] args) { Example example = new Example(); Thread t1 = new Thread1(example); Thread t2 = new Thread2(example); t1.start(); t2.start(); }}class Example{ public synchronized void execute() { for (int i = 0; i < 20; ++i) { try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Hello: " + i); } } public synchronized void execute2() { for (int i = 0; i < 20; ++i) { try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("World: " + i); } }}class Thread1 extends Thread{ private Example example; public Thread1(Example example) { this.example = example; } @Override public void run() { example.execute(); }}class Thread2 extends Thread{ private Example example; public Thread2(Example example) { this.example = example; } @Override public void run() { example.execute2(); }} If the synchronized keyword is removed, the two methods are executed concurrently and have no mutual influence.
But as written in the example subroutine, even two methods:
The execution result is always the output of one thread and then the execution of another thread.
illustrate:
If an object has multiple synchronized methods, and a thread has entered a synchronized method at a certain moment, then other threads cannot access any synchronized methods of the object before the method is executed.
in conclusion:
When the synchronized keyword modifies a method, the method is called the synchronization method.
Each object in Java has a lock, or a monitor. When a thread accesses the synchronized method of an object, the object is locked, and no other thread can access the synchronized method of the object (here refers to all synchronization methods, not just the same method). It is not until the previous thread completes the execution method (or throws an exception), the lock of the object is released, so that other threads can access the synchronized method of the object again.
Note that the object is locked at this time. If it is a different object, there is no restriction relationship between the objects.
When trying to construct a second thread object in the code, a new Example object is passed in, then there is no restriction between the execution of the two threads.
3. Consider static synchronization methods
When a synchronized keyword modified method is also modified by static, it has been said before that a non-static synchronization method will lock the object, but the static method does not belong to the object, but a class, and it will lock the Class object of the class where this method is located.
No matter how many objects a class generates, they correspond to the same Class object.
Example Program 3
public class ThreadTest{ public static void main(String[] args) { Example example = new Example(); Thread t1 = new Thread1(example); // Even if different objects are passed here, static method synchronization still does not allow multiple threads to execute at the same time. Example = new Example(); Thread t2 = new Thread2(example); t1.start(); t2.start(); }}class Example{ public synchronized static void execute() { for (int i = 0; i < 20; ++i) { try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Hello: " + i); } } public synchronized static void execute2() { for (int i = 0; i < 20; ++i) { try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("World: " + i); } }}class Thread1 extends Thread{ private Example example; public Thread1(Example example) { this.example = example; } @Override public void run() { Example.execute(); }}class Thread2 extends Thread{ private Example example; public Thread2(Example example) { this.example = example; } @Override public void run() { Example.execute2(); }} So if it is a static method (execute() and execute2() both have static keywords added), even if different Example objects are passed to two threads, the two threads are still restricted by each other. One must be executed first and then the next one.
in conclusion:
If a synchronized method is static, when a thread accesses the method, it locks not the object where the synchronized method is located, but the Class object corresponding to the class where the synchronized method is located. In Java, no matter how many objects a class has, these objects will correspond to a unique Class object. Therefore, when a thread accesses two static and synchronized methods of two objects of the same class, their execution order is also sequential, that is, one thread executes the method first, and the other thread starts after the execution is completed.
4. Synchronized block
Synchronized block writing method:
synchronized(object) { } It means that the thread will lock the object object when it is executed. (Note that this object can be an object of any class, or you can use this keyword).
This way, you can specify the locked object by yourself.
Example Program 4
public class ThreadTest{ public static void main(String[] args) { Example example = new Example(); Thread t1 = new Thread1(example); Thread t2 = new Thread2(example); t1.start(); t2.start(); }}class Example{ private Object object = new Object(); public void execute() { synchronized (object) { for (int i = 0; i < 20; ++i) { try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Hello: " + i); } } } public void execute2() { synchronized (object) { for (int i = 0; i < 20; ++i) { try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("World: " + i); } } } }}class Thread1 extends Thread{ private Example example; public Thread1(Example example) { this.example = example; } @Override public void run() { example.execute(); }}class Thread2 extends Thread{ private Example example; public Thread2(Example example) { this.example = example; } @Override public void run() { example.execute2(); }} The effect achieved by Example Program 4 is the same as that of Example Program 2. Both threads are executed in sequence, rather than concurrently. When one thread executes, the object object is locked, and the other thread cannot execute the corresponding block.
The synchronized method is actually equivalent to wrapping all statements in the method with a synchronized block, and then passing this keyword in the brackets of the synchronized block. Of course, if it is a static method, the class object needs to be locked.
Perhaps only a few lines of code in a method will involve thread synchronization issues, so the synchronized block controls the access of multiple threads more granularly than the synchronized method. Only the content in the synchronized block cannot be accessed by multiple threads at the same time, and other statements in the method can still be accessed by multiple threads at the same time (including before and after the synchronized block).
Note: The data protected by synchronized should be private.
in conclusion:
The synchronized method is a coarse-grained concurrent control. At a certain moment, only one thread can execute the synchronized method;
Synchronized block is a fine-grained concurrency control, which only synchronizes the code in the block. Other codes located in the method and other than synchronized blocks can be accessed by multiple threads at the same time.