In Java, the synchronized keyword is used to control thread synchronization, which prevents synchronized code from being executed by multiple threads in a multithreaded environment.
Synchronized is a Java keyword and a type of synchronization lock. It modifies the following objects:
- Modifies a block of code, called a synchronous block, that acts on code enclosed in curly braces {} and on the object that calls the block.
- Modify a method. The modified method is called a synchronous method. The scope of the modified method is the whole method and the object is the object that calls the method.
- Modify a static method that applies to the entire static method and to all objects of the class.
- Modifies a class whose scope is the part enclosed in parentheses after synchronized, and whose main objects are all objects of the class.
1. When a thread accesses a synchronized(this) block in an object, other threads attempting to access the object are blocked. [Demo1] : synchronized
1 /** 2 */ 4 class thread implements Runnable {5 private static int count; 6 7 public SyncThread() { 8 count = 0; 9 } 10 11 public void run() { 12 synchronized(this) { 13 for (int i = 0; i < 5; i++) { 14 try { 15 System.out.println(Thread.currentThread().getName() + ":" + (count++)); 16 Thread.sleep(100); 17 } catch (InterruptedException e) { 18 e.printStackTrace(); 19 } 20 } 21 } 22 } 23 24 public int getCount() { 25 return count; 26}} 27Copy the code
Call to SyncThread:
1 SyncThread syncThread = new SyncThread();
2 Thread thread1 = new Thread(syncThread, "SyncThread1");
3 Thread thread2 = new Thread(syncThread, "SyncThread2");
4 thread1.start();
5 thread2.start();
Copy the code
The results are as follows:
SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread2:7
SyncThread2:8
SyncThread2:9
Copy the code
When two concurrent threads (thread1 and thread2) access a synchronized block in the same object (syncThread), only one thread can be executed at a time. The other thread is blocked and must wait for the current thread to complete its execution before executing the block. Thread1 and thread2 are mutually exclusive because the current object is locked when a synchronized block is executed. The lock cannot be released until the block is executed, and the next thread can execute and lock the object. Let’s change the call to SyncThread a bit:
1 Thread thread1 = new Thread(new SyncThread(), "SyncThread1");
2 Thread thread2 = new Thread(new SyncThread(), "SyncThread2");
3 thread1.start();
4 thread2.start();
Copy the code
The results are as follows:
SyncThread1:0
SyncThread2:1
SyncThread1:2
SyncThread2:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread1:7
SyncThread1:8
SyncThread2:9
Copy the code
Doesn’t it say that when one thread executes a synchronized block, the other thread blocks? Why are thread1 and Thread2 executing at the same time in the above example? This is because synchronized only locks objects, and each object has only one lock associated with it, and the above code is equivalent to this code:
1 SyncThread syncThread1 = new SyncThread();
2 SyncThread syncThread2 = new SyncThread();
3 Thread thread1 = new Thread(syncThread1, "SyncThread1");
4 Thread thread2 = new Thread(syncThread2, "SyncThread2");
5 thread1.start();
6 thread2.start();
Copy the code
This creates two SyncThread objects, syncThread1 and syncThread2. Thread1 executes the synchronized code (run) of the syncThread1 object. Thread2 executes synchronized code (run) in the syncThread2 object; We know that synchronized locks objects, and two locks are used to lock syncThread1 and syncThread2 objects respectively. These two locks are non-interfering and do not form a mutual exclusion, so two threads can execute simultaneously.
2. When one thread accesses a synchronized(this) synchronized block of an object, another thread can still access the non-synchronized (this) synchronized block of the object. [Demo2] : Multiple threads access synchronized and non-synchronized code blocks
1 class Counter implements Runnable { 2 private int count; 3 4 public Counter() { 5 count = 0; 6 } 7 8 public void countAdd() { 9 synchronized(this) { 10 for (int i = 0; i < 5; i ++) { 11 try { 12 System.out.println(Thread.currentThread().getName() + ":" + (count++)); 13 Thread.sleep(100); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16} 17} 18} 19} 20 Synchronized 22 public void printCount() {23 for (int I = 0; synchronized 22 public void printCount() {23 for (int I = 0; i < 5; i ++) { 24 try { 25 System.out.println(Thread.currentThread().getName() + " count:" + count); 26 Thread.sleep(100); 27 } catch (InterruptedException e) { 28 e.printStackTrace(); 29 } 30 } 31 } 32 33 public void run() { 34 String threadName = Thread.currentThread().getName(); 35 if (threadName.equals("A")) { 36 countAdd(); 37 } else if (threadName.equals("B")) { 38 printCount(); 39} 40} 41}./* Welcome to Java chatCopy the code
Calling code:
1 Counter counter = new Counter();
2 Thread thread1 = new Thread(counter, "A");
3 Thread thread2 = new Thread(counter, "B");
4 thread1.start();
5 thread2.start();
Copy the code
The results are as follows:
A:0
B count:1
A:1
B count:2
A:2
B count:3
A:3
B count:4
A:4
B count:5
Copy the code
CountAdd is synchronized; printCount is not synchronized. As you can see from the above results, when one thread accesses the synchronized block of an object, other threads can access the non-synchronized block of the object without blocking.
Demo3: Specifies that an object is to be locked
1 /** 2 * 3 */ 4 class Account {5 String name; 6 float amount; 7 8 public Account(String name, float amount) { 9 this.name = name; 10 this.amount = amount; Public void deposit(float amt) {14 amount += amt; 15 try { 16 Thread.sleep(100); 17 } catch (InterruptedException e) { 18 e.printStackTrace(); 19 public void withdraw(float amt) {23 amount -= amt; 24 try { 25 Thread.sleep(100); 26 } catch (InterruptedException e) { 27 e.printStackTrace(); 28 } 29 } 30 31 public float getBalance() { 32 return amount; 33} 34} 35 36 /** 37 * AccountOperator implements Runnable {40 private Account Account; 41 public AccountOperator(Account account) { 42 this.account = account; 43 } 44 45 public void run() { 46 synchronized (account) { 47 account.deposit(500); 48 account.withdraw(500); 49 System.out.println(Thread.currentThread().getName() + ":" + account.getBalance()); 50} 51} 52}Copy the code
Calling code:
1 Account Account = new Account(" Zhang SAN ", 10000.0f); 2 AccountOperator accountOperator = new AccountOperator(account); 3 4 final int THREAD_NUM = 5; 5 Thread threads[] = new Thread[THREAD_NUM]; 6 for (int i = 0; i < THREAD_NUM; i ++) { 7 threads[i] = new Thread(accountOperator, "Thread" + i); 8 threads[i].start(); 9}./* Welcome to join Java communication Q sample: 909038429Copy the code
The results are as follows:
Thread3:10000.0 Thread2:10000.0 Thread1:10000.0 Thread4:10000.0 Thread0:10000.0 Thread3:10000.0 Thread2:10000.0 Thread1:10000.0 Thread4:10000.0 Thread0:10000.0Copy the code
In the Run method of the AccountOperator class, we lock the Account object with synchronized. At this point, when one thread accesses the Account object, other threads attempting to access the Account object will block until that thread finishes accessing the Account object. That means whoever gets the lock can run the code it controls. When you have an explicit object as a lock, you can write programs like the following.
1 public void obj (SomeObject obj) {2 synchronized(obj) {4 // todo 5} 6}Copy the code
A special object can be created to act as a lock when there is no explicit object to use as a lock and you just want to synchronize a piece of code:
1 class Test implements Runnable { 2 private byte[] lock = new byte[0]; Public void method() {4 synchronized() {5 public void run() {7} 8 9 public void run() {10 11} 12}Copy the code
Note: Zero-length byte array objects are more economical to create than any Object — look at the compiled bytecode: generating a zero-length byte[] Object requires only three opcodes, whereas Object Lock = new Object() requires seven lines of opcodes.
Public Synchronized void method(){//todo}; A synchronized modifier is similar to a modifier block, except that the scope is different. A modifier block is a range enclosed in braces, whereas a modifier range is the entire function. If the run method in Demo1 is changed to the following way, the effect is the same.
* [Demo4] : synchronized modifies a method
1 public synchronized void run() { 2 for (int i = 0; i < 5; i ++) { 3 try { 4 System.out.println(Thread.currentThread().getName() + ":" + (count++)); 5 Thread.sleep(100); 6 } catch (InterruptedException e) { 7 e.printStackTrace(); 8} 9} 10}Copy the code
Synchronized acts on the whole method. Writing a:
1 public synchronized void method() {
2 // todo
3 }
Copy the code
Method 2:
1 public void method() {
2 synchronized(this) {
3 // todo
4 }
5 }
Copy the code
Note 1 modifies a method, while note 2 modifies a block of code, but note 1 and note 2 are equivalent in locking the contents of the entire method.
Note the following when using synchronized modifiers:
- The synchronized keyword cannot be inherited.
Although synchronized can be used to define methods, synchronized is not part of the method definition, and therefore the synchronized keyword cannot be inherited. If a method in a parent class uses the synchronized keyword and a method in a subclass overrides it, the method in the subclass is not synchronized by default, and you must explicitly add the synchronized keyword to the method in the subclass. Of course, you can also call the parent method in a subclass method, so that even though the method in the subclass is not synchronized, the subclass calls the parent’s synchronized method, so that the method in the subclass is synchronized. Example code for both methods is as follows: Add the synchronized keyword to the subclass method
1 class Parent {
2 public synchronized void method() { }
3 }
4 class Child extends Parent {
5 public synchronized void method() { }
6 }
Copy the code
Call the synchronous method of the parent class in a subclass method
1 class Parent { 2 public synchronized void method() { } 3 } 4 class Child extends Parent { 5 public void method() { 6 super.method(); 8 7}}Copy the code
2. Do not use the synchronized keyword when defining interface methods. 3. The constructor cannot use the synchronized keyword, but can use a synchronized code block for synchronization. Modify a static method Synchronized also modifies a static method:
1 public synchronized static void method() {
2 // todo
3 }
Copy the code
We know that static methods belong to classes, not objects. Similarly, synchronized modified static methods lock all objects of the class. Let’s make some changes to Demo1 as follows:
[Demo5] : synchronized modifies static methods
1 /** 2 */ 4 class thread implements Runnable {5 private static int count; 6 7 public SyncThread() { 8 count = 0; 9 } 10 11 public synchronized static void method() { 12 for (int i = 0; i < 5; i ++) { 13 try { 14 System.out.println(Thread.currentThread().getName() + ":" + (count++)); 15 Thread.sleep(100); 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 } 20 } 21 22 public synchronized void run() { 23 method(); 25 24}}Copy the code
Calling code:
1 SyncThread syncThread1 = new SyncThread();
2 SyncThread syncThread2 = new SyncThread();
3 Thread thread1 = new Thread(syncThread1, "SyncThread1");
4 Thread thread2 = new Thread(syncThread2, "SyncThread2");
5 thread1.start();
6 thread2.start();
Copy the code
The results are as follows:
SyncThread1:0
SyncThread1:1
SyncThread1:2
SyncThread1:3
SyncThread1:4
SyncThread2:5
SyncThread2:6
SyncThread2:7
SyncThread2:8
SyncThread2:9
Copy the code
SyncThread1 and syncThread2 are two objects of SyncThread, but maintain thread synchronization when thread1 and thread2 execute concurrently. This is because run calls the static method, which belongs to the class, so syncThread1 and syncThread2 use the same lock. This is different from Demo1.
Modifying a class Synchronized can also apply to a class as follows:
1 class name {2 public void method() {3 synchronized(classname.class) {4 // todo 5} 6} 7}. 909038429 Blow water and chat togetherCopy the code
Let’s make some more changes to Demo5. [Demo6] : Modifies a class
1 /** 2 */ 4 class thread implements Runnable {5 private static int count; 6 7 public SyncThread() { 8 count = 0; 9 } 10 11 public static void method() { 12 synchronized(SyncThread.class) { 13 for (int i = 0; i < 5; i ++) { 14 try { 15 System.out.println(Thread.currentThread().getName() + ":" + (count++)); 16 Thread.sleep(100); 17 } catch (InterruptedException e) { 18 e.printStackTrace(); 19 } 20 } 21 } 22 } 23 24 public synchronized void run() { 25 method(); 26}} 27Copy the code
The effect of synchronized is the same as that of [Demo5]. When synchronized acts on a class T, it locks the class T, and all objects of T use the same lock.
Summary: a. Whether synchronized is added to A method or an object, if the object it acts on is non-static, then it acquires the lock as an object; If synchronized acts on a static method or a class, it acquires the same lock for all objects of that class. B. Each object has only a lock associated with it. Whoever holds this lock can run the code it controls. C. Implementing synchronization is expensive and can even cause deadlocks, so avoid unnecessary synchronization control.
Mysql, Netty, Spring, thread, Spring Cloud, JVM, source code, algorithm, etc., also have a detailed learning plan map, interview questions, etc., need to obtain these contents of the friend please add Q: sample: 909038429/./* Welcome to Java chat