当前位置:网站首页>Synchronized solves problems caused by sharing
Synchronized solves problems caused by sharing
2022-07-06 08:21:00 【Sit in the sunny window and drink tea alone】
The problem of sharing
Small cases
The initial value of two thread pairs is 0 One of the static variables is self increasing , One does self subtraction , Do it separately 5000 Time , The result is 0 Do you ?
package cn.knightzz.example;
import lombok.extern.slf4j.Slf4j;
@SuppressWarnings("all")
@Slf4j(topic = "c.TestShareValue")
public class TestShareValue {
static int value = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
value++;
log.debug("value + 1 = {}", value);
}
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
value--;
log.debug("value - 1 = {}", value);
}
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
log.debug("value : {} ", value);
}
}
Problem analysis
The above result may be positive 、 negative 、 zero . Why? ? because Java Autoincrement of static variables in , Self subtraction is not an atomic operation , Be thorough
Explain , Must be analyzed from bytecode
For example, for i++ for (i Is a static variable ), The actual results are as follows JVM Bytecode instruction :
getstatic i // Get static variables i Value
iconst_1 // Prepare constants 1
iadd // Self increasing
putstatic i // Store the modified value in a static variable i
And the corresponding i-- It's similar :
getstatic i // Get static variables i Value
iconst_1 // Prepare constants 1
isub // Self reduction
putstatic i // Store the modified value in a static variable i
and Java The memory model of is as follows , Complete the self increment of static variables , Self subtraction requires data exchange between main memory and working memory :
If it is single thread or above 8 Line code is executed sequentially ( It won't interlace ) No problem :
In the case of negative numbers :
Critical resources
There is no problem for a program to run multiple threads
- The problem is that multiple threads access shared resources
In fact, there is no problem for multiple threads to read shared resources
- Instruction interleaving occurs when multiple threads read and write to shared resources , There will be problems
If there are multithreaded read and write operations on shared resources in a code block , Call this code block a critical area
static int counter = 0;
public void increment(){
// A critical region
counter++;
}
public void decrement(){
counter--;
}
Race condition
Multiple threads execute in a critical area , The results are unpredictable due to the different execution sequences of the code , It is called a race condition
synchronized Solution
Mutually exclusive
In order to avoid the occurrence of race conditions in the critical region , There are many ways to get there :
- Blocking solutions :synchronized,Lock
- Non blocking solution : Atomic variable
synchronized Object lock , At most one thread can hold at the same time by mutual exclusion Object lock , When other threads try to get the lock of this object again, they will block . This ensures that the thread with the lock can safely execute the code in the critical area , Don't worry about thread context switching
although java Mutual exclusion and synchronization in synchronized Keyword to complete , But they are different :
- Mutual exclusion is to ensure that the race condition in the critical region occurs , Only one thread can execute critical area code at a time
- Synchronization is due to the sequence of thread execution 、 Different order 、 A thread needs to wait for other threads to run to a certain point
synchronized( object ) // Threads 1, Threads 2(blocked)
{
A critical region
}
Small cases
package cn.knightzz.test;
import lombok.extern.slf4j.Slf4j;
@SuppressWarnings("all")
@Slf4j(topic = "c.TestSynchronized")
public class TestSynchronized {
private static int counter = 0;
public static void main(String[] args) throws InterruptedException {
method2();
}
private static void method1() throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
log.debug("counter add : {} ", counter);
counter++;
}
log.debug("t1 thread end ... ");
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
log.debug("counter sub : {} ", counter);
counter--;
}
log.debug("t2 thread end ... ");
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
// The end result may be Positive numbers , A negative number or 0
log.debug("method1 : counter = {}", counter);
// Reset counter
counter = 0;
}
private static void method2() throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 500000; i++) {
synchronized (TestSynchronized.class) {
// Use static class objects as lock
log.debug("counter add : {} ", counter);
counter++;
}
}
log.debug("t1 thread end ... ");
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 500000; i++) {
synchronized (TestSynchronized.class) {
log.debug("counter sub : {} ", counter);
counter--;
}
}
log.debug("t2 thread end ... ");
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
// The end result may be Positive numbers , A negative number or 0
log.debug("method2 : counter = {}", counter);
// Reset counter
counter = 0;
}
}
synchronized It can be considered as the key to a room , The critical area can be considered as a room
- When the thread gets the lock , Will enter the room and close the door , here Other threads cannot enter the critical zone Code to execute critical area
- As shown above , Threads 2 At the door , You will find the door closed , And threads 2 Can't get lock , So it can only be blocked , Wait for thread 1 Release the lock at the end of execution
- Another thing to note : It's not that you can carry out it all the time after you get the lock , CPU Assign to thread 1 After the end of the time slice , Threads 1 Will be kicked out of the critical zone , Then the door was locked again .
- At this time, the thread is still holding the lock , Wait until the thread 1 Get... Again CPU After the time slice , Code to complete critical area , After releasing the lock , Threads 2 Then you can get the lock and enter the critical area to execute the code in the critical area
The diagram is as follows :
Atomic understanding
for (int i = 0; i < 50000; i++) {
synchronized (TestSynchronized.class) {
// Use static class objects as lock
log.debug("counter add : {} ", counter);
counter++;
}
}
Like the code above , here synchronized
The package is counter++;
This line of code , The operation is counter
This critical resource
counter++
stay jvm There are four step instructions :
- get static i Get static variables i
- iconst Prepare constants
- iadd Self increasing
- putstatic take i The value of is written to Static variables
Atomicity is to ensure , this The four steps are an integral whole , Before these four steps are completed , No thread can get the lock , Once these four steps are completed , Then the lock will be released , therefore t1 Threads and t2 Threads can alternately mix and print
Thinking and summary
synchronized In fact, object lock is used to ensure the atomicity of the code in the critical region , The code in the critical area is inseparable from the outside , Will not be cut by the thread
Change places to interrupt
Think about the following : ?
- If you put synchronized(obj) Put it in for Outside of the loop , How to understand ?-- Atomicity
- If t1 synchronized(obj1) and t2 synchronized(obj2) How it will work ?-- Lock object
- If t1 synchronized(obj) and t2 What happens if you don't add ? How to understand ?-- Lock object
problem 1 :
- If you put synchronized(obj) Put it in for Outside of the loop , How to understand ?-- Atomicity
What should be noted in the above figure is : When a counter++
perhaps counter--
After execution , The object lock will be released , That's why two threads print alternately , If you put it in for Out of the loop , that for A cycle is a whole , It's atomic , Before the end of execution , Other threads cannot get the lock , therefore At this time, print successively , Print out thread 1 in the future , Will print threads 2
We can think of the place where the critical area code is stored as a house , This house has only one door , Different critical area code resources are stored in the house
// t1 Threads
synchronized (TestSynchronized.class) {
// Use static class objects as lock
log.debug("counter add : {} ", counter);
counter++;
}
// t2 Threads
synchronized (TestSynchronized.class) {
log.debug("counter sub : {} ", counter);
counter--;
}
You can see the code above , All of them are TestSynchronized.class
This class object , TestSynchronized.class
It's a lock object , This lock object corresponds to a room ( A critical region ) , There is synchronized
Critical area code of the package , Whenever the corresponding thread wants to execute the corresponding code , Get the lock first .
Back to the question , If synchronized
stay for
Outer package of circulation , be
for
A loop is a critical code , When the thread acquires the lock , Will directly put for The loop is finished , The lock will release- Whole for The cycle will be considered as a whole , Single thread for Before the loop execution ends , Will not be disturbed by other threads
- What you can see intuitively is The program will print first t1 perhaps t2 Output , wait until t1 perhaps t2 After execution , Will execute the code of another thread
If it is wrapped in counter++
On :
synchronized (TestSynchronized.class) {
log.debug("counter sub : {} ", counter);
counter--;
}
getstatic i // obtain i Variable
iconst_1 // Prepare constants 1
iadd // i Self increasing 1
putstatic i // take 1 Write to i
Because of the addition of synchronized
, The four lines above JVM Instructions are a whole , There is no interference by other threads before these four lines of instructions have been executed , such as : Execute to **iadd**
after Prepare to carry out **putstatic i**
Thread context switching , Command interrupt ! , Before these four instructions are executed , Will not be interrupted by any thread
You can see t1 and t2 In fact, it is mixed and operated alternately
If it is wrapped in for Out of the loop :
synchronized (TestSynchronized.class) {
for (int i = 0; i < 5000; i++) {
// Use static class objects as lock
log.debug("counter add : {} ", counter);
counter++;
}
}
Like the code above , amount to for The cycle is considered as a whole , It's atomic , that , stay for Before the end of cycle execution , No interference from other threads
Intuitive feeling , t1 After execution , t2 Only when the lock object is obtained, the execution begins
problem 2 :
- If t1 synchronized(obj1) and t2 synchronized(obj2) How it will work ?-- Lock object
If two lock objects are different , But if the same critical resource is operated , It is equivalent to no lock and no mutual exclusion :
As shown in the figure above : Equivalent to two rooms , Because the locks are different , A lock can be understood to correspond to a room , So when threads 1 obtain testQuestion1
Lock time of , Not with threads 2 Mutual exclusion occurs , Does not affect threads 2 obtain testQuestion2
lock , So the final result is the same as not locking
It can also be understood as opening another door , At the same time , Both threads can enter the room to modify critical resources
problem 3
- If t1 synchronized(obj) and t2 What happens if you don't add ? How to understand ?-- Lock object
If one is locked , The other one doesn't add , It's also equivalent to not adding , because t2 Threads can execute at will , You can modify the value of critical resources without obtaining locks
reflection
In fact, if you want to ensure atomicity , Must be mutually exclusive , Make sure that , All critical area codes are in one room , That is to say, you need to use the same lock
otherwise , As long as there is a critical area not in this room , Then atomicity cannot be guaranteed , Because the code execution of this critical area is unlimited , You can modify critical resources at will
Object oriented improvement
Put the shared variables that need to be protected into a class
package cn.knightzz.improve;
import lombok.extern.slf4j.Slf4j;
@SuppressWarnings("all")
@Slf4j(topic = "c.Room")
public class Room {
private int counter = 0;
public void increment() {
// Use the current object as the lock
synchronized(this) {
log.debug("increment counter : {} " , counter);
counter++;
}
}
public void decrement() {
// Use the current object as the lock
synchronized(this) {
log.debug("decrement counter : {} " , counter);
counter--;
}
}
public int getCounter() {
return counter;
}
}
Then call directly when using Room
The method provided can
package cn.knightzz.improve;
import cn.knightzz.test.TestSynchronized;
import lombok.extern.slf4j.Slf4j;
/** * @author Wang Tianci * @title: TestObjectImprove * @projectName hm-juc-codes * @description: Object oriented improvement * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a> * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a> * @create: 2022-07-03 21:09 */
@SuppressWarnings("all")
@Slf4j(topic = "c.Room")
public class TestObjectImprove {
public static void main(String[] args) throws InterruptedException {
Room room = new Room();
Thread t1 = new Thread(() -> {
// stay for In the process of loop execution , No interference from other threads
for (int i = 0; i < 5000; i++) {
room.increment();
}
log.debug("t1 thread end ... ");
}, "t1");
Thread t2 = new Thread(() -> {
// stay for In the process of loop execution , No interference from other threads
for (int i = 0; i < 5000; i++) {
room.decrement();
}
log.debug("t2 thread end ... ");
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
log.debug("counter : {} ... ", room.getCounter());
}
}
边栏推荐
猜你喜欢
The Vice Minister of the Ministry of industry and information technology of "APEC industry +" of the national economic and information technology center led a team to Sichuan to investigate the operat
"Designer universe": "benefit dimension" APEC public welfare + 2022 the latest slogan and the new platform will be launched soon | Asia Pacific Financial Media
"Designer universe" APEC design +: the list of winners of the Paris Design Award in France was recently announced. The winners of "Changsha world center Damei mansion" were awarded by the national eco
National economic information center "APEC industry +": economic data released at the night of the Spring Festival | observation of stable strategy industry fund
Nft智能合约发行,盲盒,公开发售技术实战--拼图篇
C语言 - 位段
CISP-PTE实操练习讲解
Convolution, pooling, activation function, initialization, normalization, regularization, learning rate - Summary of deep learning foundation
Understanding of law of large numbers and central limit theorem
From monomer structure to microservice architecture, introduction to microservices
随机推荐
华为云OBS文件上传下载工具类
08- [istio] istio gateway, virtual service and the relationship between them
[research materials] 2021 Research Report on China's smart medical industry - Download attached
All the ArrayList knowledge you want to know is here
Résumé des diagrammes de description des broches de la série ESP
Char to leading 0
[Yugong series] February 2022 U3D full stack class 011 unity section 1 mind map
CAD ARX gets the current viewport settings
将 NFT 设置为 ENS 个人资料头像的分步指南
IP lab, the first weekly recheck
Migrate data from CSV files to tidb
远程存储访问授权
matplotlib. Widgets are easy to use
Analysis of Top1 accuracy and top5 accuracy examples
TiDB备份与恢复简介
It's hard to find a job when the industry is in recession
Flash return file download
LDAP application (4) Jenkins access
Vocabulary notes for postgraduate entrance examination (3)
Configuring OSPF load sharing for Huawei devices