java - 除非我使用 .join(),否则为什么同步方法不会被锁定?
问题描述
在Java
中,标记一个方法synchronized
应该禁用由两个线程调用该方法导致的竞争条件,该方法正在访问和修改同一对象中的字段。
但由于某种原因,synchronized
除非我.join()
在主程序中调用两个线程,否则在以下示例中无法按预期工作。这是为什么?
package example;
public class Account {
private double balance;
public Account(double balance) {
super();
this.balance = balance;
}
public synchronized void deposit(double amount) {
balance += amount;
}
public double getBalance() {
return balance;
}
}
package example;
public class AccountTester extends Thread {
private Account account;
private double amount;
public AccountTester(Account account, double amount) {
this.account = account;
this.amount = amount;
}
public static void main(String[] args) {
Account account = new Account(0);
AccountTester tester1 = new AccountTester(account, 1.0);
AccountTester tester2 = new AccountTester(account, 2.0);
tester1.start();
tester2.start();
// Why do I need the main thread to join threads
// tester1 and tester2 for synchronized to work?
try {
tester1.join();
tester2.join();
} catch (InterruptedException e) {
System.err.println(e);
}
System.out.println("End balance: " + account.getBalance());
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
account.deposit(amount);
}
}
}
解决方案
正如@flakes 所阐明的那样,代码需要两个线程的主线程join()
来保证两个线程都被终止,即在打印出 end 之前完成对余额的修改balance
。
实现这一点的一种更简洁的方法是使用java.util.concurrent.ExecutorService
接口。这里它的shutdown()
方法保证线程池中的两个线程都在打印结束之前完成balance
。这是我的实现:
package example;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class AccountTester implements Runnable {
private Account account;
private double amount;
public AccountTester(Account account, double amount) {
this.account = account;
this.amount = amount;
}
public static void main(String[] args) {
Account account = new Account(0);
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.execute(new AccountTester(account, 1.0));
executorService.execute(new AccountTester(account, 2.0));
executorService.shutdown();
System.out.println("End balance: " + account.getBalance());
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
account.deposit(amount);
}
}
}
推荐阅读
- python - 您如何使用“while true”定义一个函数以使错误的用户输入循环回到 Python 3.8 上的行首
- java - MapStruct - 找不到类型的返回值的转换器
- sql - 如何解决 pgadmin 上的错误 23505?
- date - CakePHP - Date::i18nFormat() 大写
- angular - Angular 通用“npm run prerender”命令永不停止
- postgresql - 为什么我的 postgresql csv 导出的行数比表多?
- django - Django collectstatic 不会从 react npm build 文件夹中收集媒体文件
- assembly - 汇编程序 - 使用显示字符串而不是寄存器
- javascript - Javascript - 基于键值的连接/更新字典数组
- c - 枚举的乐趣:在 C 中是否允许将变量定义为枚举类型,然后将变量初始化为枚举中不包含的值?