preface
Tip: when you read this article, you must have a strong desire to learn about multithreading. Then this article will describe in detail the simple use and in-depth understanding of Synchronized keywords, deadlocks, simple use in thread communication, waiting notification mechanism, thread lounge, producer and consumer operation value and stack, simple use and implementation principle of ThreadLocal, introduction to ForkJoin and other thread related knowledge
Tip: if you don't have a solid thread foundation, please refer to Java multithreading development from simple to difficult (I)
https://blog.csdn.net/yuanjiangwei255/article/details/118879188?spm=1001.2014.3001.5501
1, synchronized keyword
1. Why use synchronized
Before understanding this section, you need to understand that + + operators have two steps: add first and then assign a value, such as I + + 1 i+1 2. i=i+1
Example
package com.yjw.unit3; import java.util.concurrent.TimeUnit; /** * <Brief function > < br > * <> * * @author : Yuan Jiangwei * @date : Created in 2021/7/25 17:14 * @description: * @modified By: * @version: 1.0.0 */ public class Test1 { public static void main(String[] args) { Ticket ticket = new Ticket(); Thread t1 = new Thread(ticket,"Ticket gate 1"); Thread t2 = new Thread(ticket,"Ticket gate 2"); t1.start(); t2.start(); //TODO, if we new two Ticket objects, there is no problem, but the multithreading problem often occurs in "multiple threads operate on one object" } } class Ticket implements Runnable{ private int index = 0; //Ten tickets altogether private final int Max = 10; @Override public void run() { while(index < Max){ try { //At this point, we let all threads sleep for one second TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } index++; System.out.println(Thread.currentThread().getName()+"Ticket number:"+index); } } }
Console output:
Ticket number at ticket gate 1:2 Ticket number at ticket gate 2:2 Ticket number at ticket gate 1:3 Ticket number at ticket gate 2:4 Ticket number at ticket gate 1:5 Ticket number at ticket gate 2:6 Ticket number at ticket gate 1:7 Ticket number at ticket gate 2:7 Ticket number at ticket gate 1:8 Ticket number at ticket gate 2:9 Ticket number at ticket gate 1:10 Ticket number at ticket gate 2:11
We observed that the problem with the ticketing system is still great
Summarize three questions:
1. Ticket number 1 disappeared?
2. Ticket No. 2 was sold twice?
3. There is No. 11 ticket larger than 10?
Next, let's analyze them one by one
Why1. Ticket number 1 disappeared?
Thread execution is scheduled by CPU time slice polling
When window 1 is executed to index=1, the and output in the future will be returned
The CPU suddenly stops window 1 to execute window 2
Form 2 changes the index to 2 and outputs it
Form 1 continues to output 2
Why2. Ticket number 2 was sold twice?
why1 can also cause
There is another case when window 1 has not been assigned (note that index + + is divided into two steps. At this moment, the second step why1 is assigned)
Execute the assignment of window 2, and the output is 2
Execute the assignment of window 1, and the output is 2
Why3. There's an 11 ticket bigger than 10?
When index is 9
Window 1 passed the while condition
Execute window 2 immediately and pass the while condition
Until window 2 outputs 10
The index is not executed until the window is opened++
Output 11
legend:
Summary: data confusion caused by multiple threads operating the member variables of an object at the same time
2.synchronized is easy to use
Based on the above problems, the reason is that multiple threads operate on member variables in the same object at the same time. keyword
synchronized provides an exclusive mechanism in which only one thread can perform certain operations at the same point in time
The synchronized keyword can implement a simple strategy to prevent thread interference and memory consistency errors if an object pair is multiple
If the thread is visible, all reads or writes to the object will be synchronized.
When we add the synchronized keyword:
package com.yjw.unit3; import java.util.concurrent.TimeUnit; /** * <Brief function > < br > * <> * * @author : Yuan Jiangwei * @date : Created in 2021/7/25 17:14 * @description: * @modified By: * @version: 1.0.0 */ public class Test1 { public static void main(String[] args) { Ticket ticket = new Ticket(); Thread t1 = new Thread(ticket,"Ticket gate 1"); Thread t2 = new Thread(ticket,"Ticket gate 2"); t1.start(); t2.start(); //TODO, if we new two Ticket objects, there is no problem, but the multithreading problem often occurs in "multiple threads operate on one object" } } class Ticket implements Runnable{ private int index = 0; //Ten tickets altogether private final int Max = 10; @Override public synchronized void run() { while(index < Max){ try { //At this point, we let all threads sleep for one second TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } index++; System.out.println(Thread.currentThread().getName()+"Ticket number:"+index); } } }
Output results:
Ticket number at ticket gate 1:1 Ticket number at ticket gate 1:2 Ticket number at ticket gate 1:3 Ticket number at ticket gate 1:4 Ticket number at ticket gate 1:5 Ticket number at ticket gate 1:6 Ticket number at ticket gate 1:7 Ticket number at ticket gate 1:8 Ticket number at ticket gate 1:9 Ticket number at ticket gate 1:10
At this time, the previous three problems have been successfully solved, although only one thread is processing
Why is there only one thread executing?
The synchronized method feature allows only one thread to operate the current method
Because the current method has a while loop, only one thread executes
As long as the while method does not exit, it proves that the method has not finished executing
Other threads can only wait
Is this really good?
A: of course, the efficiency is not good, the execution is slow, and the purpose of multiple threads operating an object is not achieved
Next, we analyze the code that is easy to cause thread safety:
while(index < Max){ //Multiple threads may enter the while loop at the same time. There is a thread problem try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { //This place doesn't operate on variables. We don't care about him e.printStackTrace(); } index++; //There is a thread problem when multiple threads execute + + at the same time System.out.println(Thread.currentThread().getName()+"Ticket number:"+index); }
Next, we continue to describe the second use of synchronized (synchronized code blocks)
package com.yjw.unit3; import java.util.concurrent.TimeUnit; /** * <Brief function > < br > * <> * * @author : Yuan Jiangwei * @date : Created in 2021/7/25 19:14 * @description: * @modified By: * @version: 1.0.0 */ public class Test2 { public static void main(String[] args) { Ticket2 ticket = new Ticket2(); Thread t1 = new Thread(ticket,"Ticket gate 1"); Thread t2 = new Thread(ticket,"Ticket gate 2"); t1.start(); t2.start(); //TODO, if we new two Ticket objects, there is no problem, but the multithreading problem often occurs in "multiple threads operate on one object" } } class Ticket2 implements Runnable{ private int index = 0; //Ten tickets altogether private final int Max = 10; //Declare a lock private final Object lock = new Object(); @Override public void run() { synchronized(lock){ //Synchronous code block while(index < Max){ try { //At this point, we let all threads sleep for one second TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } index++; System.out.println(Thread.currentThread().getName()+"Ticket number:"+index); } } } }
Console output:
Ticket number at ticket gate 1:1 Ticket number at ticket gate 1:2 Ticket number at ticket gate 1:3 Ticket number at ticket gate 1:4 Ticket number at ticket gate 1:5 Ticket number at ticket gate 1:6 Ticket number at ticket gate 1:7 Ticket number at ticket gate 1:8 Ticket number at ticket gate 1:9 Ticket number at ticket gate 1:10
We found that the current synchronized code block is no different from the method synchronized
Reason: we just switch to synchronize the code block. The scope is the same as before
According to the above analysis, thread safety is isolated
package com.yjw.unit3; import java.util.concurrent.TimeUnit; /** * <Brief function > < br > * <> * * @author : Yuan Jiangwei * @date : Created in 2021/7/25 19:14 * @description: * @modified By: * @version: 1.0.0 */ public class Test2 { public static void main(String[] args) { Ticket2 ticket = new Ticket2(); Thread t1 = new Thread(ticket,"Ticket gate 1"); Thread t2 = new Thread(ticket,"Ticket gate 2"); t1.start(); t2.start(); //TODO, if we new two Ticket objects, there is no problem, but the multithreading problem often occurs in "multiple threads operate on one object" } } class Ticket2 implements Runnable{ private int index = 0; //Ten tickets altogether private final int Max = 10; //Declare a lock private final Object lock = new Object(); @Override public void run() { while(index < Max){ //We won't deal with thread safety at the moment try { //At this point, we let all threads sleep for one second TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(lock) { //Synchronous code blocks handle current thread safety issues index++; System.out.println(Thread.currentThread().getName() + "Ticket number:" + index); } } } }
Console output:
Ticket number at ticket gate 1:1 Ticket number at ticket gate 2:2 Ticket number at ticket gate 2:3 Ticket number at ticket gate 1:4 Ticket number at ticket gate 2:5 Ticket number at ticket gate 1:6 Ticket number at ticket gate 2:7 Ticket number at ticket gate 1:8 Ticket number at ticket gate 2:9 Ticket number at ticket gate 1:10 Ticket number at ticket gate 2:11
We have implemented both ticket port 1 and ticket port 2 at the same time and solved the problems of data duplication and data loss
However, there is a problem that the number is out of bounds
Cause analysis of number out of bounds
The while condition is index < Max to end the while loop
The equivalent is index > = max to end the while loop
When a thread is executed when index + + is equal to 9, it is allowed to enter the while loop
When a thread is executed when index + + is equal to 10, it is not allowed to enter the while loop
Then the thread with index++ == 9 will index again++
So the number is out of bounds
Let's optimize next:
Mentioned earlier
The while condition is index < Max to end the while loop
The equivalent is index > = max to end the while loop
package com.yjw.unit3; import java.util.concurrent.TimeUnit; /** * <Brief function > < br > * <> * * @author : Yuan Jiangwei * @date : Created in 2021/7/25 19:14 * @description: * @modified By: * @version: 1.0.0 */ public class Test2 { public static void main(String[] args) { Ticket2 ticket = new Ticket2(); Thread t1 = new Thread(ticket,"Ticket gate 1"); Thread t2 = new Thread(ticket,"Ticket gate 2"); t1.start(); t2.start(); //TODO, if we new two Ticket objects, there is no problem, but the multithreading problem often occurs in "multiple threads operate on one object" } } class Ticket2 implements Runnable{ private int index = 0; //Ten tickets altogether private final int Max = 10; //Declare a lock private final Object lock = new Object(); @Override public void run() { while(true){ //Processing is converted to judgment in synchronous code blocks try { //At this point, we let all threads sleep for one second TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(lock) { //The synchronous code block handles the current thread safety problem. When 9 that thread comes in, the index has been changed to 10 if(index >= Max){ break; } index++; System.out.println(Thread.currentThread().getName() + "Ticket number:" + index); } } } }
Console output:
Ticket number at ticket gate 1:1 Ticket number at ticket gate 2:2 Ticket number at ticket gate 1:3 Ticket number at ticket gate 2:4 Ticket number at ticket gate 2:5 Ticket number at ticket gate 1:6 Ticket number at ticket gate 1:7 Ticket number at ticket gate 2:8 Ticket number at ticket gate 2:9 Ticket number at ticket gate 1:10
Perfect solution to ticket sales!
The keyword synchronized has different meanings when added to different places. Although they are all locked, the locked objects are different.
Specify lock object: lock the specified object and obtain the lock of the object before entering the synchronization code.
Method to act on an instance: it is equivalent to locking the current instance. Before entering the synchronization code, you need to obtain the lock of the instance
Acting on static methods: it is equivalent to locking the current class, and obtaining the lock of the current class before entering the synchronization code.
I've been busy these two days. After that, it lasts more