On thread safety
1. What is thread safety?
When multiple threads write to the same global variable (the same resource) at the same time (the read operation will not involve thread safety), if the result is the same as what we expect, we call it thread safety. On the contrary, threads are not safe.
2. Take a chestnut
Students buy train tickets during the new year, that guy, that scene, that's quite big! It's really: gongs and drums, firecrackers, red flags and a sea of people. Let's simulate the business scenario with code.
package com.example.snailthink; /** * @program: snailthink * @description: * @author: SnailThink * @create: 2021-09-03 14:19 **/ public class MyThread implements Runnable { private int ticketCount=50; @Override public void run() { try { while (ticketCount<50){ Thread.sleep(50); } }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+": Grab the second"+ticketCount--+"Zhang"); } }
Test class
package com.example.snailthink; /** * @program: snailthink * @description: * @author: SnailThink * @create: 2021-09-03 14:09 **/ public class MyThreadTests{ private int count=50; public static void main(String[] args) { MyThread myThread = new MyThread(); Thread thread = new Thread(myThread,"petty thief"); Thread thread1 = new Thread(myThread,"Xiao Zhang"); Thread thread2 = new Thread(myThread,"Xiao Wang"); thread.start(); thread1.start(); thread2.start(); } }
Operation results
Through the above test results, three threads grab tickets at the same time, sometimes they will grab the same ticket? Why is there such a problem found?
Before answering this question, we should take a look at Java's memory model (JMM)
3. What is JMM?
**JMM(Java Memory Model), * * is a mechanism and specification based on computer memory model to ensure that Java programs can access memory under various platforms with consistent effects. Ensure the atomicity, visibility and order of shared memory
Visibility: when multithreading operates the shared memory, the execution results can be synchronized to the shared memory in time to ensure that other threads can see the results in time.
We draw the previous ticket grabbing business through the diagram.
Multiple threads in the same process share memory resources. The count of main memory is the shared resource. In fact, Xiao Li, Xiao Zhang and Xiao Wang do not directly write to the count of the main memory. Each of them has their own working memory during the running of the program. In fact, each person copies the count of the main memory to operate on the variables of their own working memory. After the operation, the corresponding result is notified to the main memory.
The reason why the simulation ticket grabbing demo has thread safety problems is:
Because they operate their own working memory, they start to operate when they get the value of the main memory. Suppose that at this time, the count is 23. At the same time, there are two threads, and the value of the working memory of these two threads is 23. As a result, these two threads will grab the ticket of 23.
4. How to solve the thread safety problem?
To solve the problem of thread safety, we need to solve a problem, that is, synchronous interaction between threads. After knowing the visibility, we know that there is no way to manipulate each other's working memory.
There are generally the following methods
- synchronized keyword (placed on method)
- Synchronous code block
- jdk1.5 Lock
4.1 synchronized keyword (placed on the method)
package com.example.snailthink.test.thread; /** * @program: snailthink * @description: * @author: SnailThink * @create: 2021-09-03 14:43 **/ public class MySynchronizedThread implements Runnable { private int count=50; @Override public void run() { while(true){ buy(); } } public synchronized void buy(){ if(count>0){ try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+": Grab the second"+count--+"Zhang,"+System.currentTimeMillis()); } } }
test result
Through the picture, we can find that at the same time, the interval of ticket grabbing is almost 50ms. Why does multithreading fail???
Because synchronized is added to the ticket grabbing method, only one thread can run at the same time. After this thread runs, the next thread can run.
4.2 synchronization code block
-
This way is to use synchronized + lock objects
-
Compared with the synchronized method, the performance is improved. Only code blocks are locked instead of all methods.
package com.example.snailthink.test.thread; /** * @program: snailthink * @description: * @author: SnailThink * @create: 2021-09-03 14:41 **/ public class SynchronizedBlockThreadTest implements Runnable { private int count = 50; private Object object = new Object(); @Override public void run() { while (true) { buy(); } } public void buy() { synchronized (object) { if (count > 0) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ": Grab the second" + count-- + "Zhang," + System.currentTimeMillis()); } } } }
4.3 jdk1.5 Lock
package com.example.snailthink.test.thread; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @program: snailthink * @description: * @author: SnailThink * @create: 2021-09-03 14:40 **/ public class LockThreadTests implements Runnable { private int count = 50; //Define lock object private Lock lock = new ReentrantLock(); @Override public void run() { while (true) { buy(); } } public void buy() { lock.lock(); if (count > 0) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ": Grab the second" + count-- + "Zhang," + System.currentTimeMillis()); } lock.unlock(); } }