Three problems in concurrent programming
1. Visibility
/** * When one thread modifies a shared variable, another thread cannot get the latest value immediately */ public class Test01 { private static Boolean flag = true; public static void main (String[] args) { new Thread(() -> { while (flag) { } }).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { flag = false; System.out.println("flag Update to false"); }).start(); } }
Summary:
During concurrent programming, there will be visibility problems. When one thread modifies a shared variable, the other thread does not immediately see the latest modified value.
2. Atomicity
/** * Define 5 threads, and each thread adds the variable num to 1000 In the case of thread safety, Num is finally equal to 5000 */ public class Test02 { private static int num = 0; public static void main (String[] args) { Runnable run = () -> { for (int i = 1; i <= 1000; i++) { num++; } }; List<Thread> threads = new ArrayList<>(); for (int i = 0; i < 5; i++) { Thread thread = new Thread(run); threads.add(thread); thread.start(); } for (Thread t : threads) { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("num:" + num); } }
Summary:
num + + is not an atomic operation.
In concurrent programming, there will be atomicity problems. When one thread operates half of the shared variables, another thread may also operate the shared variables, interfering with the operation of the previous thread.
3. Order
Jcstress is a Java Concurrent pressure measurement tool. https://wiki.openjdk.java.net/display/CodeTools/jcstress
Modify pom file and add dependency:
<dependency> <groupId>org.openjdk.jcstress</groupId> <artifactId>jcstress-core</artifactId> <version>${jcstress.version}</version> </dependency>
I_Result is an object with an attribute r1 to save the result. How many results may occur in the case of multithreading?
- Thread 1 executes actor 1 first. At this time, ready = false, so the result of entering else branch is 1.
- Thread 2 executes to actor 2 and executes num = 2; And ready = true, thread 1 executes. This time, it enters the if branch, and the result is
4. - Thread 2 executes actor 2 first and only executes num = 2; However, thread 1 executes before it has time to execute ready = true, and it still enters
else branch, the result is 1. - There is another result 0.
Thread 2 executes actor 2 first, and reordering occurs. It executes ready = true first, and num = 2 has not been executed yet; Thread 1 executes. The default value of num is 0, and the result is 0
Three problems in concurrent programming are solved by synchronized
1. Visibility
public class Test01 { private static Boolean flag = true; public static void main (String[] args) { new Thread(() -> { while (flag) { //System.out.println(flag); It can also be implemented with this, because the bottom layer uses synchronized synchronized (Test01.class){ //lock: flag to get the latest value from the main memory } } }).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { flag = false; System.out.println("flag Update to false"); }).start(); } }
Summary:
Synchronized is the principle of ensuring visibility. When synchronized is executed, it will correspond to the lock atomic operation and refresh the shared variables in the working memory
Value of quantity
2. Atomicity
public class Test02 { private static int num = 0; private static Object obj=new Object(); public static void main (String[] args) { Runnable run = () -> { for (int i = 1; i <= 1000; i++) { synchronized (obj) { num++; } } }; List<Thread> threads = new ArrayList<>(); for (int i = 0; i < 5; i++) { Thread thread = new Thread(run); threads.add(thread); thread.start(); } for (Thread t : threads) { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("num:" + num); } }
The principle of synchronized ensuring atomicity
For number + +; After adding synchronous code blocks, ensure that only one thread operates number + +; at the same time;. There will be no security problems.
Summary
Synchronized ensures atomicity. Synchronized ensures that only one thread gets the lock and can enter the synchronized code block.
3. Order
Causes of previous problems
Thread 2 executes actor 2 first, and reordering occurs. It executes ready = true first, and num = 2 has not been executed yet; Thread 1 executes, Num defaults to 0, and the result is 0
How
Thread 2 executes actor 2 first, and reordering occurs. It executes ready = true first, and num=2 has not been executed yet; Thread 1 executes. At this time, thread 1 cannot get the lock, so thread 1 can only execute after thread 2 finishes executing num=2 and releases the lock, because num will not be equal to 0 again
The principle of synchronized ensuring order
After synchronized, although reordering is carried out to ensure that only one thread will enter the synchronized code block, it can also ensure order.
Summary
The principle that synchronized ensures order. After we add synchronized, reordering will still occur. However, we have synchronized code blocks, which can ensure that only one thread executes the code in the synchronized code. Ensure order
synchronized feature - reentrant feature
public class Test02 { public static void main (String[] args) { Runnable sellTicket = new Runnable() { @Override public void run () { synchronized (Test02.class) { System.out.println("I am run"); test01(); } } public void test01 () { synchronized (Test02.class) { System.out.println("I am test01"); } } }; new Thread(sellTicket).start(); new Thread(sellTicket).start(); } }
Reentrant principle
There is a counter (recursions variable) in the synchronized lock object that records how many times the thread obtains the lock
Reentrant benefits
- Deadlock can be avoided
- Can let us better encapsulate the code
Summary
synchronized is a reentrant lock. In the internal lock object, there will be a counter recording thread to obtain the lock several times. When the synchronization code block is executed, the number of counters will be - 1. When the number of counters is 0, release the lock.
Source: https://www.bilibili.com/video/BV1aJ411V763?p=19&spm_id_from=pageDriver