【问题标题】:Why is the synchronized method not getting locked unless I use .join()?除非我使用 .join(),否则为什么同步方法不会被锁定?
【发布时间】:2019-06-18 01:55:46
【问题描述】:

在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);
        }
    }
}

【问题讨论】:

  • 与synchronized方法无关。如果你不join 程序将退出而不等待线程实际做任何工作。启动线程不是即时的,请尝试使用 sleep(1000) 而不是 join 并查看差异。
  • 谢谢@flakes。这对我的理解很有帮助。

标签: java concurrency synchronized


【解决方案1】:

正如@flakes 所澄清的那样,代码需要主线程到join() 两个线程,以保证两个线程都被终止,即在打印出结尾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);
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-13
    • 2014-06-07
    • 1970-01-01
    • 2019-02-08
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多