【问题标题】:Synchronization in java giving unexpected outputjava中的同步给出了意外的输出
【发布时间】:2017-03-03 10:15:39
【问题描述】:

我正在看一本书,看到一段代码说下面的代码是线程同步的:

//账户类

 public class Account {

 private double balance;

 public double getBalance() {
 return balance;
}

 public void setBalance(double balance) {
 this.balance = balance;
}


 public synchronized void addAmount(double amount) {
 double tmp=balance;
 try {
 Thread.sleep(10);
 } catch (InterruptedException e) {
   e.printStackTrace();
 }
 tmp+=amount;
 balance=tmp;
}


public synchronized void subtractAmount(double amount) {
  double tmp=balance;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
tmp-=amount;
balance=tmp;
}

}

//银行类

public class Bank implements Runnable {

 private Account account;
 public Bank(Account account) {
  this.account=account; 
}

@Override

public void run() {

for (int i=0; i<1000; i++){

     account.subtractAmount(1000);
  }
 }
}

//公司类

public class Company implements Runnable {

 private Account account;

 public Company(Account account) {
    this.account=account;
}

@Override

 public void run() {
   for (int i=0; i<1000; i++){
   account.addAmount(1000);
   }
  }
}

//主类

 public class Main {
 public static void main(String[] args) {
 Account account=new Account();
 account.setBalance(1000);
 Company company=new Company(account);
 Thread companyThread=new Thread(company);
 Bank bank=new Bank(account);
 Thread bankThread=new Thread(bank);
 System.out.printf("Account : Initial Balance: %f\n",account.
 getBalance());
 companyThread.start();
 bankThread.start();

 try {
   companyThread.join();
   bankThread.join();
   System.out.printf("Account : Final Balance: %f\n",account.
   getBalance());
 } 
    catch (InterruptedException e) {
    e.printStackTrace();
  }
 }
}

这里两个不同对象的两个线程使用 addAmount 和 subAmount 函数同时更改 balance 变量,但它总是给出正确的输出作为 Initial 和 Final balance 相同,即 1000.000 。我的意思是他们应该给我一些问题,因为两个线程同时在同一个变量上工作。

请纠正我哪里出错了。 提前致谢

【问题讨论】:

  • 这就是你使用synchronized的原因
  • 其实这本书并不完全正确。您可以设置不同步的余额。只有加减法是。你能告诉我们这是什么书吗?

标签: java multithreading synchronization thread-safety


【解决方案1】:

这就是同步的重点。它确保一次只有一个线程可以执行该函数。

【讨论】:

    【解决方案2】:

    在 Java 中发生的事情是每个对象都有一个 intrisinc 锁,而 synchronize 关键字的使用表明当一个线程(我们称之为 A)调用该方法时,线程 A 持有该锁。当线程 A 持有锁时,其他线程将被阻止访问对象的同步部分(在您的情况下为 Account 对象)。

    一旦线程 A 完成了同步块(或本例中的方法)的执行,线程 A 就会释放对象上的锁,其他等待访问您的 Account 对象的线程现在可以继续前进。

    • 首先,对同一对象的同步方法的两次调用不可能交错。当一个线程正在执行时 对象的同步方法,调用的所有其他线程 同一对象块的同步方法(暂停执行) 直到第一个线程处理完对象。
    • 其次,当一个同步方法退出时,它会自动与任何后续的方法建立一个happens-before关系 为同一对象调用同步方法。这 保证对象状态的更改对所有人可见 线程。

    请参阅https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html 了解有关使用同步的更多详细信息。

    实际上,为了使 Account 线程安全,您可能希望同步设置器并将余额声明为 volatile:

    public class Account {
    
     private volatile double balance;
    
     public double getBalance() {
     return balance;
     }
    
     public synchronized void setBalance(double balance) {
     this.balance = balance;
    }
    

    //其余代码已经同步 }

    有关 volatile 使用的更多信息,请参阅 https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html

    【讨论】:

      猜你喜欢
      • 2020-12-29
      • 1970-01-01
      • 1970-01-01
      • 2016-03-11
      • 2013-07-15
      • 1970-01-01
      • 1970-01-01
      • 2018-05-21
      • 2020-07-05
      相关资源
      最近更新 更多