尽管保护写操作仍获取竞争条件 - Java
使用 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 接口如下:
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());
}
}
最后我的 Main 类
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 条件,而另一个线程无限期地继续。我很困惑!
Using the java.util.concurrent.locks.ReentrantLock library as follows:
Two threads generate a random number and use it to update the shared variables account1 and account2 stored in class Accounts - a lock is used to protect the writing to the shared vars
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;
}
}
My threads implement the Runnable interface as follows:
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());
}
}
and finally my Main class
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());
}
}
that looks a little longer than i thought it would - apologies. I would expect that neither of the threads would terminate, because account1+account2 should always = 0 as the mutex handles protecting the updating of account1 and account2. What seems to happen is that one of the threads exits because it fails the account1+account2==0 condition, and the other one continues indefinitely. im confused!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这是因为你没有锁定吸气剂上的读取。这意味着线程 2 可以读取不一致状态的数据,而线程 1 正在更新数据(在 += 和 -= 之间)。
该问题可能发生如下:
线程 1:
线程 2:
线程 1:
解决方案:
不幸的是,您不能简单地单独同步您的 getter,我建议使用一种新的 get 方法:
并在 RaceThread.run() 中将 while 条件更改为:
It's because you're not locking the reads on your getters. This means thread 2 can read the data in an inconsistent state, while thread 1 is updating the data (between += and -=).
The problem can happen as follows:
Thread 1:
Thread 2:
Thread 1:
The solution:
Unfortunately you can't simply synchonize your getters individually I would instead recommend a new get method:
and in
RaceThread.run()
change the while condition to:仅仅同步你的写入是不够的;您还需要使用相同的锁/监视器来同步读取。
如果不这样做,可能会发生不好的事情:
account1
的旧值和account2
的新值,反之亦然。It's not enough to synchronize your writes; you also need to synchronize your reads, using the same lock/monitor.
If you don't, bad things can happen:
account1
and a new value ofaccount2
, or vice-versa.您仅同步对变量的写访问。
因此,有可能一个线程将 account1 设置为新值,而另一个线程正在读取旧的 account2。
you are only syncronizing the write access to the variables.
so there is a chance of one thread setting account1 to a new value while the other is reading an old account2.
您的 Getter 未锁定。因此,即使您在更新时使用互斥体,另一个线程也会调用可以解锁运行的 Getters。
公共 int getAccounts(){
整数结果 = 0;
尝试{
互斥体.lock();
结果=账户1+账户2;
}catch(异常前){
System.out.println(ex);
}最后{mutex.unlock();}
返回结果;
}
Your Getters are not locked. So even though you use a mutex on updating the other thread is calling the Getters which can run unlocked.
public int getAccounts(){
int result = 0;
try{
mutex.lock();
result = account1 + account2;
}catch(Exception ex){
System.out.println(ex);
}finally{mutex.unlock();}
return result;
}