gpt4 book ai didi

java - 了解 Java 多线程中的内存可见性

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:37:49 25 4
gpt4 key购买 nike

我最近试图围绕一些 Java 多线程概念进行思考,并编写了一小段代码来帮助我理解内存可见性和尽可能正确地获得同步。根据我读过的内容,似乎我们持有锁的代码量越少,我们的程序的效率就越高(通常)。我写了一个小类来帮助我理解一些我可能会遇到的同步问题:

public class BankAccount {
private int balance_;

public BankAccount(int initialBalance) {
if (initialBalance < 300) {
throw new IllegalArgumentException("Balance needs to be at least 300");
}
balance_ = initialBalance;
}

public void deposit(int amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Deposit has to be positive");
}
// should be atomic assignment
// copy should also be non-shared as it's on each thread's stack
int copy = balance_;

// do the work on the thread-local copy of the balance. This work should
// not be visible to other threads till below synchronization
copy += amount;

synchronized(this) {
balance_ = copy; // make the new balance visible to other threads
}
}

public void withdraw(int amount) {
// should be atomic assignment
// copy should also be non-shared as it's on each thread's stack
int copy = balance_;

if (amount > copy) {
throw new IllegalArgumentException("Withdrawal has to be <= current balance");
}

copy -= amount;

synchronized (this) {
balance_ = copy; // update the balance and make it visible to other threads.
}
}

public synchronized getBalance() {
return balance_;
}
}

请忽略 balance_ 应该是 double 而不是整数这一事实。我知道基本类型的读取/赋值是原子的,除了 double 和长整型,所以我选择了 int 以简单起见

我尝试在函数内部写注释来描述我的想法。编写此类是为了获得正确的同步并最大程度地减少处于锁定状态的代码量。这是我的问题:

  1. 此代码是否正确?它会遇到任何数据/竞争条件吗?其他线程是否可以看到所有更新?
  2. 此代码是否与仅进行方法级同步一样高效?我可以想象,随着我们所做工作量的增加(这里,它只是一个加法/减法),它可能会导致方法级同步方面的严重性能问题。
  3. 能否使这段代码更有效率?

最佳答案

任何不在同步块(synchronized block)内的代码都可以由多个线程并发执行,您的解决方案是在同步块(synchronized block)之外创建新的平衡,因此它无法正常工作。让我们看一个例子:

int copy = balance_; // 1

copy += amount; //2

synchronized(this) {
balance_ = copy; // 3
}
  1. 当程序开始时,我们有 _balance = 10
  2. 然后我们启动 2 个线程,试图将余额加 10 和 15
  3. 线程1给变量copy赋值10
  4. 线程2给变量copy赋值10
  5. 线程2加15复制赋值给_balance -> 25
  6. 线程1加10复制赋值给_balance ->20

最后 BankAccount 有 20 但它应该是 35

正确的做法是:

public class BankAccount {
private int balance_;

public BankAccount(int initialBalance) {
if (initialBalance < 300) {
throw new IllegalArgumentException("Balance needs to be at least 300");
}
balance_ = initialBalance;
}

public void deposit(int amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Deposit has to be positive");
}

synchronized(this) {
balance_ += amount;
}
}

public void withdraw(int amount) {
synchronized (this) {
if (amount > balance_) {
throw new IllegalArgumentException("Withdrawal has to be <= current balance");
}

balance_ -= amount;
}
}

public synchronized int getBalance() {
return balance_;
}
}

关于java - 了解 Java 多线程中的内存可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38730405/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com