当前位置:网站首页>Thread safety analysis of [concurrent programming JUC] variables
Thread safety analysis of [concurrent programming JUC] variables
2022-07-01 08:15:00 【Looking at the stars】
List of articles
Whether member variables and static variables are thread safe ?
- If they don't share , Then thread safety
- If they're shared , Depending on whether their state can be changed , There are two more cases
- If there are only read operations , Then thread safety
- If there are read and write operations , Then this code is a critical area , Thread safety needs to be considered
Local variables are thread safe ?
- Local variables are thread safe
- But the objects referenced by local variables may not be
- If the object does not escape the function of the method, access , It's thread safe
- If the object escapes the scope of the method , Thread safety needs to be considered
1 Local variable analysis
Test code :
@Slf4j(topic = "test4")
public class test4 {
public static void test() {
int i = 10;
i++;
}
}
Bytecode ( Compile the code first , Decompiling again :javap -v test4.class
)
public static void test();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=0
0: bipush 10
2: istore_0
3: iinc 0, 1
6: return
LineNumberTable:
line 18: 0
line 19: 3
line 20: 6
LocalVariableTable:
Start Length Slot Name Signature
3 4 0 i I
Call per thread test() When the method is used , local variable i Multiple copies will be created in the stack frame memory of each thread , So there is no sharing .
2 Comparative analysis of member variables and local variables
ThreadUnsafe
Class has member variables list
And three ways ,method2 The way is to list Add elements to it ,method3 It's from list Remove elements from .
When two threads work together on the same list Object time , The following will happen : Threads 1 The added element is not written into memory by the thread 2 interrupt , Threads 2 Add elements and write them into memory , After that thread 1 Then write it into memory , Two additions are equivalent to only one addition , Then remove it twice , There will be errors .
public class TestThreadSafe {
static final int THREAD_NUMBER = 2;
static final int LOOP_NUMBER = 200;
public static void main(String[] args) {
ThreadUnsafe test = new ThreadUnsafe();
for (int i = 0; i < THREAD_NUMBER; i++) {
new Thread(() -> {
test.method1(LOOP_NUMBER);
}, "Thread" + (i+1)).start();
}
}
}
class ThreadUnsafe {
ArrayList<String> list = new ArrayList<>();
public void method1(int loopNumber) {
for (int i = 0; i < loopNumber; i++) {
method2();
method3();
}
}
private void method2() {
list.add("1"); }
private void method3() {
list.remove(0); }
}
Report errors IndexOutOfBoundsException
:
Exception in thread "Thread1" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:659)
at java.util.ArrayList.remove(ArrayList.java:498)
at Chapter4.ThreadUnsafe.method3(TestThreadSafe.java:39)
at Chapter4.ThreadUnsafe.method1(TestThreadSafe.java:34)
at Chapter4.TestThreadSafe.lambda$main$0(TestThreadSafe.java:23)
at java.lang.Thread.run(Thread.java:748)
analysis :
- No matter which thread method2 All references are in the same object list Member variables
- method3 And method2 The analysis is the same
When put list Change the member variable to local variable :
public class TestThreadSafe {
static final int THREAD_NUMBER = 2;
static final int LOOP_NUMBER = 200;
public static void main(String[] args) {
ThreadSafe test = new ThreadSafe();
for (int i = 0; i < THREAD_NUMBER; i++) {
new Thread(() -> {
test.method1(LOOP_NUMBER);
}, "Thread" + (i+1)).start();
}
}
}
class ThreadSafe{
public void method1(int loopNumber) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < loopNumber; i++) {
method2(list);
method3(list);
}
}
private void method2(ArrayList<String> list) {
list.add("1"); }
private void method3(ArrayList<String> list) {
list.remove(0); }
}
analysis :
- list It's a local variable , Each thread creates a different instance when it calls , No sharing
- and method2 The parameters are from method1 It's from , And method1 Reference the same object in
- method3 Parameter analysis and method2 identical
- method2 and method3 It's all private methods , operation list There are only these two methods .
3 Local variable exposure reference
Thinking about method access modifiers , If you put method2 and method3 The method of is modified to public Will there be proxy thread safety issues ?
- situation 1: There are other threads calling method2 and method3
- situation 2: In the case 1 On the basis of , by ThreadSafe Class to add subclasses , Subclass coverage method2 or method3 Method , namely
class ThreadSafe{
public void method1(int loopNumber) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < loopNumber; i++) {
method2(list);
method3(list);
}
}
public void method2(ArrayList<String> list) {
list.add("1"); }
public void method3(ArrayList<String> list) {
list.remove(0); }
}
take method2 and method3 The permission modifier of is changed to public, Still thread safe at this point . because , Calling method2 and method3 yes , Operation of the list It's not in method1 Internal list.
Add subclasses ThreadSafeSubClass
Inherit ThreadSafe
, And rewrite method3 Method , Create a thread inside it to operate list.
class ThreadSafe{
public void method1(int loopNumber) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < loopNumber; i++) {
method2(list);
method3(list);
}
}
public void method2(ArrayList<String> list) {
list.add("1"); }
public void method3(ArrayList<String> list) {
list.remove(0); }
}
class ThreadSafeSubClass extends ThreadSafe{
@Override
public void method3(ArrayList<String> list) {
new Thread(() -> {
list.remove(0);
}).start();
}
}
At this point, there will be a thread safety problem , because method1 establish list The object operation list, call method3 Another thread will be created to operate this list, Multiple threads share list, There will be thread safety issues .
As can be seen from the example private and final Provide 【 Security 】 The significance of .
private Methods that modify cannot be overridden .
final Prevent subclasses from overriding methods .
4 Common thread safety classes
- String
- Integer
- StringBuffer
- Random
- Vector
- Hashtable
- java.util.concurrent Class under package
By saying that they are thread safe, I mean , When multiple threads call a method of their same instance , It's thread safe . It can also be understood as
- Each of their methods is atomic
- But note that the combination of their multiple methods is not atomic , See the analysis later
5 Combination of thread safe class methods
Analyze whether the following code is thread safe ?
Hashtable table = new Hashtable();
// Threads 1, Threads 2
if (table.get("key") == null) {
table.put("key", "value");
}
The possible execution order is as follows :
Ideally , There may only be one thread put; But it's also possible that a thread put End , By another thread put Cover . Cover the previous situation , Missing updates .
Every method in a thread safe class can guarantee atomicity , But composition does not guarantee atomicity . If you want the combination to ensure atomicity , You need to add a protection on the outside of the combination .
6 Immutable thread safety
String、Integer And so on are immutable classes , Because of its internal state ( attribute ) Can't change ( Only read , Can't change ), Therefore, their methods are thread safe
but ,String Yes replace, substring And other methods can change the value , So how do these methods ensure thread safety ?
see String Source code , Among them substring Method creates a new string , It is not a modification of the original string .
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
7 The example analysis
example 1:
Servlet Running on the Tomcat In the environment , There is only one example , Will be tomcat Shared by multiple threads , Therefore, there will be sharing problems among the member variables .
- Map map: Not thread safe , Non thread safe class ,HashTable It's thread safe .
- String S1: Thread safety , Because it is an immutable class .
- final String S2: Same thread safety .
- Date D1: Not thread safe , Non thread safe class .
- final Date D2:Date The object of D2 The reference value of cannot be changed , But the attribute in the date ( Specific date ) You can change , Not thread safe . An immutable reference to an object does not mean that the state of the object is immutable .
example 2:
From the bottom up :
- DAO No member variables , Even if multiple threads access , There is no state to modify , So it's thread safe .
- Connection Is a local variable in a method , Even if there are multiple threads , Other threads cannot access ( Each thread creates a separate Connection), It's also thread safe .
- Service It contains private member variables , But there is nothing else to change it , It is immutable , So it's thread safe .
example 3:
here Connection by DAO Local variables of ,Servelet Only one copy. , therefore Service Only one copy. , therefore DAO Only one copy. , therefore DAO It must be shared by multiple threads , So the variables will be shared by multiple threads . therefore , Not thread safe .
such as , Threads 1 You just created Connection, It's not working yet , Threads 2 Just take Connection Use , After using close, Then there is something wrong with the opportunity .
example 4:
And example 4 comparison ,Dao identical , but Service Different . On each call Service when , Will recreate a new Dao, No will Dao As a Service Member variables of .
Dao by Service Local variables of inner methods , Each new thread creates a new Dao, new Dao It will create a new one Connection, So there will be no thread safety issues . But this way is not very good .
example 5:
although SimpleDateFormat Is the script variable , But it can be achieved through abstract methods foo Exposed to the outside . Its subclasses may have done some improper methods .
among foo I'm not sure about your behavior , May lead to unsafe occurrence , It's called Extraterrestrial method .
Methods or properties that do not want to be exposed are set to final
.String
That's what the implementation of .
8 exercises
Selling tickets
@Slf4j(topic = "ExerciseSell")
public class ExerciseSell {
public static void main(String[] args) throws InterruptedException {
// Simulate multiple people buying tickets
TicketWindow window = new TicketWindow(1000);
// Statistics of the number of tickets sold
List<Integer> amountList = new Vector<>();
// A combination of all threads
List<Thread> threadList = new ArrayList<>();
// Selling tickets
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(() -> {
// Buy tickets
int amount = window.sell(randomAmount());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
amountList.add(amount);
});
threadList.add(thread);
thread.start();
}
// Wait for the thread to finish running
for (Thread thread : threadList) {
thread.join();
}
// Count the number of votes sold and the number of remaining votes
log.debug(" Surplus ticket :{}", window.getCount());
log.debug(" Number of tickets sold :{}", amountList.stream().mapToInt(i->i).sum());
}
// Random Thread safe
static Random random = new Random();
// Random 1-5
public static int randomAmount() {
return random.nextInt(5) + 1;
}
}
/** * Ticket window */
class TicketWindow {
private int count;
public TicketWindow(int count) {
this.count = count;
}
public int getCount() {
return count;
}
public int sell(int amount) {
if (count >= amount) {
count -= amount;
return amount;
} else {
return 0;
}
}
}
Running more than once may cause errors : The number of votes sold + The number of votes left != Initial votes
Find the critical zone , A critical region : Multithreaded read and write operations on shared resources
Selling tickets window Inside count It's a shared variable
int amount = window.sell(randomAmount());
This is also a shared variable , But it's thread safe .
amountList.add(amount);
So as long as the shared variables involved in the ticket selling action are thread safe , add to synchronized
public synchronized int sell(int amount) {
if (count >= amount) {
count -= amount;
return amount;
} else {
return 0;
}
}
边栏推荐
- 手工挖XSS漏洞
- Li Kou daily question - day 31 -1502 Judge whether an arithmetic sequence can be formed
- [force deduction 10 days SQL introduction] Day9 control flow
- Codeworks round 803 (Div. 2) VP supplement
- Precautions and skills in using regular expressions in golang
- 图扑软件通过 CMMI5 级认证!| 国际软件领域高权威高等级认证
- 【入门】输入n个整数,输出其中最小的k个
- 栈实现计算器
- Day5: scanner object, next() and nextline(), sequential structure, selection structure, circular structure
- 【无标题】
猜你喜欢
CPU design practice - Chapter 4 practical tasks - simple CPU reference design and debugging
Significance and measures of source code encryption
Gdip - hatchbrush pattern table
LM08丨网格系列之网格反转(精)
[question brushing] character statistics [0]
软键盘高度报错
How to use layui to display the data in the database in the form of tables
0 basic introduction to single chip microcomputer: how to use digital multimeter and precautions
【入门】输入整型数组和排序标识,对其元素按照升序或降序进行排序
使用 setoolkit 伪造站点窃取用户信息
随机推荐
Practice and Thinking on the architecture of a set of 100000 TPS im integrated message system
Find the nearest n-th power of 2
LM08丨网格系列之网格反转(精)
【入门】输入整型数组和排序标识,对其元素按照升序或降序进行排序
力扣每日一题-第31天-202.快乐数
防“活化”照片蒙混过关,数据宝“活体检测+人脸识别”让刷脸更安全
XX攻击——反射型 XSS 攻击劫持用户浏览器
01 NumPy介绍
【入门】取近似值
Li Kou daily question - day 31 -202 Happy number
Access report realizes subtotal function
Differential: definition of total differential, partial derivative, gradient
Deep learning systematic learning
Principle and process of embossing
使用beef劫持用户浏览器
力扣每日一题-第32天-1822.数组元素积的符号
CPU设计实战-第四章实践任务一简单CPU参考设计调试
Php laraver Wechat payment
On June 30, 2022, the record of provincial competition + national competition of Bluebridge
Insufficient executors to build thread pool