使用 java.util.concurrent.locks.ReentrantLock 库如下:
两个线程生成一个随机数,并用它来更新存储在类 Accounts 中的共享变量 account1 和 account2 - 使用锁来保护对共享变量的写入
package osproj221;
import java.util.concurrent.locks.ReentrantLock;
public class Accounts {
private int account1,account2;
private final ReentrantLock mutex;
public Accounts(){
account1=account2=0;
mutex = new ReentrantLock();
}
public void updateAccounts(int amt){
try{
mutex.lock();
account1 += amt;
account2 -= amt;
}catch(Exception ex){
System.out.println(ex);
}finally{mutex.unlock();}
}
public int getAccount1(){
return this.account1;
}
public int getAccount2(){
return this.account2;
}
}
我的线程实现 Runnable 接口(interface)如下:
package osproj221;
import java.util.Random;
public class RaceThread implements Runnable {
private Random myRand = new Random();
private int counter = 0;
private Accounts accounts;
public RaceThread(Accounts accounts){
this.accounts = accounts;
}
public void run(){
do{
int r = myRand.nextInt(300);
r = Math.abs(r);
accounts.updateAccounts(r);
counter++;
}while((accounts.getAccount1() + accounts.getAccount2() == 0));
System.out.println(counter + " " + accounts.getAccount1() + " " + accounts.getAccount2());
}
}
最后是我的主课
package osproj221;
public class Main {
public static void main(String[] args) {
Accounts myAccounts = new Accounts();
Thread t1 = new Thread(new RaceThread(myAccounts));
Thread t2 = new Thread(new RaceThread(myAccounts));
t1.start();
t2.start();
try{
t1.join();
t2.join();
}catch(Exception ex){
System.out.println(ex);
}
System.out.println(myAccounts.getAccount1() + " " + myAccounts.getAccount2());
}
}
看起来比我想象的要长一些 - 抱歉。我希望两个线程都不会终止,因为 account1+account2 应始终 = 0,因为互斥体负责保护 account1 和 account2 的更新。似乎发生的情况是,其中一个线程退出,因为它未满足 account1+account2==0 条件,而另一个线程无限期地继续。我很困惑!
最佳答案
这是因为您没有锁定 setter/getter 上的读取。这意味着线程 2 可以读取不一致状态的数据,而线程 1 正在更新数据(在 += 和 -= 之间)。 该问题可能发生如下:
主题 1:
- 更新帐户(5);
- 获取锁定
- 账户1 += 5; -> 账户1 = 0 + 5; -> 账户1 = 5;
主题 2:
- getAccount1() <- 返回 5
- getAccount2() <- 返回 0
- 5+0 != 0 --> 退出
主题 1:
- 账户2 -= 5 -> 账户2 = 0-5 -> 账户2 = -5;
- 释放锁定。
解决方案: 不幸的是,您不能简单地单独同步您的 getter,我建议使用一种新的 get 方法:
public int getAccountsSum() {
try {
mutex.lock();
return this.account1 + this.account2;
} finally { mutex.unlock(); }
并在RaceThread.run()
中将while条件更改为:
}while((accounts.getAccountsSum() == 0));
关于java - 尽管保护写操作仍获取竞争条件 - Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7161153/