java 中的线程同步问题
Issue with synchronizing threads in java
我正在尝试编写一个示例程序,其中包含一个可以修改金额的银行帐户对象,以及 10 个从属对象,每个对象从 2 个不同的银行帐户移动 1 单位货币一百万次对象。我的预期结果是银行账户货币的总和最终为 0,就像我开始的那样。我已经尝试同步 BankAccount 中的 "setBalance" 方法,因为我认为这是应该同步的方法,但它不起作用。当我在 getBalance 或 运行 上尝试时,即使那些也不起作用,所以我不确定我做错了什么。
BankAccount.java
public class BankAccount{
private int balance;
public BankAccount()
{
balance = 0;
}
public int getBalance()
{
return balance;
}
public void setBalance(int balance)
{
this.balance = balance;
}
}
Slave.java
public class Slave extends Thread {
BankAccount source;
BankAccount target;
int currency = 1;
public Slave (BankAccount source, BankAccount target) {
this.source = source;
this.target = target;
}
public void run() {
for (int i = 0; i < 1000000; i++)
{
target.setBalance(target.getBalance() + currency);
source.setBalance(source.getBalance() - currency);
}
}
}
Master.java
public class Master {
public static void main(String[] args) {
BankAccount account1 = new BankAccount();
BankAccount account2 = new BankAccount();
Slave[] slaves = new Slave[10];
for (int i = 0; i < 10; i++)
{
if (i < 5)
{
slaves[i] = new Slave(account1, account2);
}
else
{
slaves[i] = new Slave(account2, account1);
}
}
for (int i = 0; i < 10; i++)
{
slaves[i].start();
}
try
{
for (Slave s : slaves)
s.join();
}
catch (InterruptedException e) {
System.out.println("Interruption before completion of the joins" + e);
}
System.out.println("Sum of balances: " + (account1.getBalance() + account2.getBalance()));
}
}
如果在方法签名中使用 synchronized
关键字,则会锁定被调用的对象。如果你想锁定一个替代对象,你需要这样使用关键字:
synchronized(objectToLock) {
doAtomicStuff();
}
在你的例子中,你的原子操作是获取、调整和设置余额,你会想要锁定相关的 BankAccount
对象。
这应该足以让您了解在何处以及如何使用 synchronized
。
此代码...
target.setBalance(target.getBalance() + currency);
... 仅当 target
的余额在 T1 调用 getBalance()
和调用 [=14= 之间未被其他线程修改时,才会在线程 T1 中产生预期效果].同步其中一个或两个方法不会阻止此类干预修改,并且您的多个线程正在执行其中如此多的操作,速度如此之快,以至于您很可能会遇到该问题。
因此,适当的临界区包含 两个 方法调用,您可以通过将它们放在 synchronized
块中来实现它们:
synchronized(target) {
target.setBalance(target.getBalance() + currency);
}
当然,您需要类似地对待source
的更新。请注意,对于每个关键区域,所有竞争线程都需要在同一个对象上同步才能使同步达到预期效果。
我正在尝试编写一个示例程序,其中包含一个可以修改金额的银行帐户对象,以及 10 个从属对象,每个对象从 2 个不同的银行帐户移动 1 单位货币一百万次对象。我的预期结果是银行账户货币的总和最终为 0,就像我开始的那样。我已经尝试同步 BankAccount 中的 "setBalance" 方法,因为我认为这是应该同步的方法,但它不起作用。当我在 getBalance 或 运行 上尝试时,即使那些也不起作用,所以我不确定我做错了什么。
BankAccount.java
public class BankAccount{
private int balance;
public BankAccount()
{
balance = 0;
}
public int getBalance()
{
return balance;
}
public void setBalance(int balance)
{
this.balance = balance;
}
}
Slave.java
public class Slave extends Thread {
BankAccount source;
BankAccount target;
int currency = 1;
public Slave (BankAccount source, BankAccount target) {
this.source = source;
this.target = target;
}
public void run() {
for (int i = 0; i < 1000000; i++)
{
target.setBalance(target.getBalance() + currency);
source.setBalance(source.getBalance() - currency);
}
}
}
Master.java
public class Master {
public static void main(String[] args) {
BankAccount account1 = new BankAccount();
BankAccount account2 = new BankAccount();
Slave[] slaves = new Slave[10];
for (int i = 0; i < 10; i++)
{
if (i < 5)
{
slaves[i] = new Slave(account1, account2);
}
else
{
slaves[i] = new Slave(account2, account1);
}
}
for (int i = 0; i < 10; i++)
{
slaves[i].start();
}
try
{
for (Slave s : slaves)
s.join();
}
catch (InterruptedException e) {
System.out.println("Interruption before completion of the joins" + e);
}
System.out.println("Sum of balances: " + (account1.getBalance() + account2.getBalance()));
}
}
如果在方法签名中使用 synchronized
关键字,则会锁定被调用的对象。如果你想锁定一个替代对象,你需要这样使用关键字:
synchronized(objectToLock) {
doAtomicStuff();
}
在你的例子中,你的原子操作是获取、调整和设置余额,你会想要锁定相关的 BankAccount
对象。
这应该足以让您了解在何处以及如何使用 synchronized
。
此代码...
target.setBalance(target.getBalance() + currency);
... 仅当 target
的余额在 T1 调用 getBalance()
和调用 [=14= 之间未被其他线程修改时,才会在线程 T1 中产生预期效果].同步其中一个或两个方法不会阻止此类干预修改,并且您的多个线程正在执行其中如此多的操作,速度如此之快,以至于您很可能会遇到该问题。
因此,适当的临界区包含 两个 方法调用,您可以通过将它们放在 synchronized
块中来实现它们:
synchronized(target) {
target.setBalance(target.getBalance() + currency);
}
当然,您需要类似地对待source
的更新。请注意,对于每个关键区域,所有竞争线程都需要在同一个对象上同步才能使同步达到预期效果。