当前位置:网站首页>CAS NO lock
CAS NO lock
2022-06-13 09:05:00 【Q z1997】
Ask questions
There are the following requirements , Guarantee account.withdraw
Thread safety of withdrawal method
import java.util.ArrayList;
import java.util.List;
interface Account {
// Get the balance
Integer getBalance();
// Withdraw money
void withdraw(Integer amount);
/** * Method will start 1000 Threads , Each thread does -10 element The operation of * If the initial balance is 10000 Then the correct result should be 0 */
static void demo(Account account) {
List<Thread> ts = new ArrayList<>();
long start = System.nanoTime();
for (int i = 0; i < 1000; i++) {
ts.add(new Thread(() -> {
account.withdraw(10);
}));
}
ts.forEach(Thread::start);
ts.forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
long end = System.nanoTime();
System.out.println(account.getBalance()
+ " cost: " + (end-start)/1000_000 + " ms");
}
}
The original implementation is not thread safe
class AccountUnsafe implements Account {
private Integer balance;
public AccountUnsafe(Integer balance) {
this.balance = balance;
}
@Override
public Integer getBalance() {
return balance;
}
@Override
public void withdraw(Integer amount) {
balance -= amount;
}
}
``
Execute test code
```java
public static void main(String[] args) {
Account.demo(new AccountUnsafe(10000));
}
The result of a certain execution
330 cost: 306 ms
Solutions - lock
The first thought is to Account Object locking
class AccountUnsafe implements Account {
private Integer balance;
public AccountUnsafe(Integer balance) {
this.balance = balance;
}
@Override
public synchronized Integer getBalance() {
return balance;
}
@Override
public synchronized void withdraw(Integer amount) {
balance -= amount;
}
}
The result is
0 cost: 399 ms
Solutions - unlocked
class AccountSafe implements Account {
private AtomicInteger balance;
public AccountSafe(Integer balance) {
this.balance = new AtomicInteger(balance);
}
@Override
public Integer getBalance() {
return balance.get();
}
@Override
public void withdraw(Integer amount) {
while (true) {
int prev = balance.get();
int next = prev - amount;
if (balance.compareAndSet(prev, next)) {
break;
}
}
// It can be simplified to the following method
// balance.addAndGet(-1 * amount);
}
}
Execute test code
public static void main(String[] args) {
Account.demo(new AccountSafe(10000));
}
The result of a certain execution
0 cost: 302 ms
CAS And volatile
What I saw in front AtomicInteger Solutions for , There is no internal lock to protect thread safety of shared variables . So how does it come true ?
public void withdraw(Integer amount) {
while(true) {
// Need to keep trying , Until we succeed
while (true) {
// Like getting the old value 1000
int prev = balance.get();
// On this basis 1000-10 = 990
int next = prev - amount;
/* compareAndSet That's what I did , stay set front , Compare first prev With the current value - It's not the same ,next To void , return false It means failure such as , Other threads have subtracted , The current value has been reduced to 990 So this time of this thread 990 It's invalid , Get into while Try again next time - Agreement , With next Set to new value , return true It means success */
if (balance.compareAndSet(prev, next)) {
break;
}
}
}
}
The key is compareAndSet, Its short name is CAS ( Also have Compare And Swap That's what I'm saying ), It has to be atomic operation .
Be careful
Actually CAS The bottom is lock cmpxchg Instructions (X86 framework ), In a single core CPU And multicore CPU It can be guaranteed in all cases 【 Compare - In exchange for 】 The atomicity of
In a multicore state , A certain core performs to bring lock When instructed by ,CPU It locks the bus , When the core has finished executing this instruction , Turn on the bus again . This process will not be interrupted by the thread scheduling mechanism , Ensure the accuracy of memory operation by multiple threads , It's atomic. .
Slow motion analysis
@Slf4j
public class SlowMotion {
public static void main(String[] args) {
AtomicInteger balance = new AtomicInteger(10000);
int mainPrev = balance.get();
log.debug("try get {}", mainPrev);
new Thread(() -> {
sleep(1000);
int prev = balance.get();
balance.compareAndSet(prev, 9000);
log.debug(balance.toString());
}, "t1").start();
sleep(2000);
log.debug("try set 8000...");
boolean isSuccess = balance.compareAndSet(mainPrev, 8000);
log.debug("is success ? {}", isSuccess);
if(!isSuccess){
mainPrev = balance.get();
log.debug("try set 8000...");
isSuccess = balance.compareAndSet(mainPrev, 8000);
log.debug("is success ? {}", isSuccess);
}
}
private static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Output results
[main] try get 10000
[t1] 9000
[main] try set 8000...
[main] is success ? false
[main] try set 8000...
[main] is success ? true
volatile
When getting shared variables , To ensure the visibility of the variable , Need to use volatile modification . It can be used to modify member variables and static member variables , It can avoid the thread looking up the value of the variable from its own working cache , You have to get its value in main memory , Thread operation volatile Variables operate directly on main memory . A thread pair volatile Modification of variables , Visible to another thread .
Be careful
volatile Only the visibility of shared variables is guaranteed , Let other threads see the latest value , But it can't solve the problem of instruction interleaving ( Atomicity is not guaranteed )
CAS Must use volatile To read the latest value of the shared variable 【 Compare and exchange 】 The effect of
Why is lockless efficient
- Without a lock , Even if the retry fails , Threads are always running at high speed , There is no pause , and synchronized It will make the thread when it doesn't get the lock , A context switch has occurred , Get in the jam . Make a comparison
- Threads are like racing cars on a high speed track , At high speed , Speed super fast , Once a context switch occurs , It's like a car has to slow down 、 Stalling , When you wake up, you have to start the fire again 、 start-up 、 Speed up … Return to high-speed operation , It costs a lot
- But without lock , Because the thread needs to stay running , Additional requirements CPU Support for ,CPU It's like a high-speed track here , No extra runway , It's impossible for threads to run at high speed , Although it won't get into the jam , But because there is no time slice , It will still be operational , Or will it cause context switching .
CAS Characteristics
combination CAS and volatile Can achieve lock free concurrency , For less threads 、 Multicore CPU In the scene of .
- CAS It's based on the idea of optimistic lock : The most optimistic estimate , Not afraid of other threads to modify shared variables , Even if it changes, it doesn't matter , I'll try again if I lose something .
- synchronized It's based on the idea of pessimistic lock : The most pessimistic estimate , Prevent other threads from modifying shared variables , I'm locked. You don't want to change , I've changed it , You have a chance to .
- CAS This is lock free concurrency 、 Non blocking concurrency , Please understand the meaning of these two sentences carefully
- Because I didn't use synchronized, So threads don't get stuck , It's one of the factors in efficiency
- But if the competition is fierce , It is conceivable that retrying must occur frequently , On the contrary, efficiency will be affected
边栏推荐
- Knowledge points related to system architecture 3
- 【QNX Hypervisor 2.2 用户手册】4.5.1 构建QNX Guest
- 【网络安全渗透】如果你还不懂CSRF?这一篇让你彻底掌握
- 国债逆回购能开户吗,国债逆回购在APP上可以直接开通券商安全吗 ,买股票怎么网上开户
- Pytorch model tuning - only some layers of the pre training model are loaded
- GBase 8a磁盤問題及處理
- Gbase 8A disk problems and Solutions
- File upload JS
- 教程篇(5.0) 02. 管理 * FortiEDR * Fortinet 网络安全专家 NSE 5
- Summary of the first retrospective meeting
猜你喜欢
Tutorial (5.0) 03 Security policy * fortiedr * Fortinet network security expert NSE 5
Library management system based on wechat applet Rar (thesis + source code)
【网络安全】SQL注入新思维之webshell提权
Neo4j - CQL使用
Cesium displays a pop-up box at the specified position and moves with the map
教程篇(5.0) 01. 产品简介及安装 * FortiEDR * Fortinet 网络安全专家 NSE 5
System analysis - detailed description
Simulink如何添加模块到Library Browser
Redis fuzzy query batch deletion
Completely uninstall PostgreSQL under Linux
随机推荐
Screenshot of cesium implementation scenario
教程篇(5.0) 03. 安全策略 * FortiEDR * Fortinet 网络安全专家 NSE 5
Web page H5 wechat sharing
Onnx crop intermediate node
Implement authentication code login and remember password (cookie)
20211020 academician all drive system
Collection of various books
VBA format word (page, paragraph, table, picture)
Neo4j环境搭建
20211028 Stabilizability
Agile development practice summary-4
国债逆回购能开户吗,国债逆回购在APP上可以直接开通券商安全吗 ,买股票怎么网上开户
Diversified tables through TL table row consolidation
【安全】零基礎如何從0到1逆襲成為安全工程師
类的加载概述
20211108 det(AB)=det(A)det(B)
20211108 det(AB)=det(A)det(B)
Completely uninstall PostgreSQL under Linux
output. Interpretation of topk() function
20211005 Hermite矩阵及几个性质