我想知道是否有人可以帮助我。我是并发编程的新手,我有以下代码,有时会给我一个IllegalMonitorStateException作为一个当前没有锁的线程试图解锁。
我在OTN论坛上被告知要防止这种情况和死锁发生,我应该确保首先锁定最低的索引,但我无法弄清楚如何做到这一点。请你们其中一个指出我正确的方向。
非常感谢。
import java.util.concurrent.locks.*;
class ShuffleBase {
ReentrantLock [] locker;
int [] data;
int x;
ReentrantLock lock1;
ReentrantLock lock2;
public ShuffleBase(int [] d){
x=0;
data=d;
locker = new ReentrantLock[d.length];
while (x!=data.length)
{
locker[x]=new ReentrantLock();
x++;
}
}
/*
* Boolean method to test if both indexes are locked
* Returning their status for use in the method swap
* If locked the swap happens else the locks are
* released
*/
public boolean lockedIndex(int a, int b){
Boolean lockA = false;
Boolean lockB = false;
try{
lockA = lock1.tryLock();
lockB = lock2.tryLock();
}finally{
if (!(lockA && lockB))
{
if(lockA){
lock1.unlock();
}
if (lockB){
lock2.unlock();
}
}// end of IF ! lockA & lockB
} // End of finally
return lockA && lockB;
}// End of lockedIndex
public void swap(int a, int b){
int temp;
lock1 = locker[a];
lock2=locker[b];
//If a & b aren't the same index swap
if(a!=b)
{
if(lockedIndex(a,b))
{
try{
temp=data[b];
data[b]=data[a];
data[a]=temp;
}finally{
lock1.unlock();
lock2.unlock();
}
}
else{System.out.println("Couldn't lock");}
}
else{return;}
}//EOF Method
public void display(){
System.out.println("The array when swapped");
for(int j=0; j<data.length;j++)
{
System.out.print(data[j]+", ");
}
}// End of Display
}// EOC
谢谢大家的回答,是的,我这样做是自学/家庭作业的一部分。 我已将代码更改为以下内容,因为我认为这是Rodion建议的内容,我希望我能正确地解释您的建议。 Mtraut我也做了你建议的改变,我不敢相信我犯了这些错误:-)感谢你发现它们。
import java.util.concurrent.locks.*;
class ShuffleBase {
ReentrantLock [] locker;
int [] data;
int x=0;
public ShuffleBase(int [] d){
data=d;
locker = new ReentrantLock[d.length];
while (x!=data.length)
{
locker[x]=new ReentrantLock();
x++;
}
}
/*
* Boolean method to test if both indexes are locked
* Returning their status for use in the method swap
* If locked the swap happens else the locks are
* released
*/
private boolean lockedIndex(int a, int b){
Boolean lockA = false;
Boolean lockB = false;
try{
lockA = locker[a].tryLock();
lockB = locker[b].tryLock();
}finally{
if (!(lockA && lockB))
{
if(lockA){
locker[a].unlock();
}
if (lockB){
locker[b].unlock();
}
}// end of IF ! lockA & lockB
} // End of finally
return lockA && lockB;
}// End of lockedIndex
public void swap(int a, int b){
int temp;
//If a & b aren't the same index swap
if(a!=b)
{
if(lockedIndex(a,b))
{
try{
temp=data[b];
data[b]=data[a];
data[a]=temp;
}finally{
locker[a].unlock();
locker[b].unlock();
}
}
else{System.out.println("Couldn't lock");}
}
else{System.out.println(return;}
}//EOF Method
public void display(){
System.out.println("The array when swapped");
for(int j=0; j<data.length;j++)
{
System.out.print(data[j]+", ");
}
}// End of Display
}// EOC
再次感谢您对我迟到的回复的所有回答和道歉。
答案 0 :(得分:3)
以下是您的计划的快速解决方法:
lock1
和lock2
字段,它们是你的来源
问题。 lock1
和locker[a]
到lock2
locker[b]
与tryLock()
。您的程序没有任何死锁问题,因为您使用的是lock()
,因此您并不需要担心这一点。如果您使用lock1
,那么您需要考虑获取锁定的顺序,否则您可能会死锁(请参阅其他答案)。
现在您当前程序存在缺陷的原因是因为lock2
和lock1
字段是跨线程共享的。例如,thread-1将locker[0]
设置为lock1
,然后立即通过将locker[99]
设置为lock1
来覆盖locker[99]
,因此当thread-1尝试解锁时IllegalStateMonitorException
恰好引用了由线程2获取的{{1}}锁,因此{{1}}。
希望这可以解决它。
答案 1 :(得分:1)
我认为您的问题是您从多个线程调用swap(.., ..)
并且swap
(和lockedIndex
)方法不是线程安全的,因为成员(lock1
和{ {1}})变量可以由另一个线程设置 - 你可以lock2
一些你没有锁定的其他索引。
使用unlock
可能会很棘手,如果你无法获得锁定,你会怎么做?
我会在论坛上找到解决方案的人 - 以特定的顺序锁定索引,以获取有关您遇到的问题的更多信息,请参阅Dining philosophers problem。
以下是您重新编写代码以使用tryLock
代替:
lock()
答案 2 :(得分:1)
我认为你是在做一些学习或家庭作业的一部分来学习并发性吗?如果没有,请考虑重新设计......
那就是说,我进一步假设要完成的任务是随机地从多个线程调用“swap”。那么你的程序很可能会立即失败,因为你在实例变量中持有“lock1”和“lock2”。这些不是本地线程 - 当涉及到“lockedIndex”时,其他一些线程可能会覆盖这些值,因此最终解锁它们是不可预测的。删除此变量并始终通过“locker []”访问“这应该适用于IllegalMonitorState ...
在此之后,您将遇到死锁(如其他论坛中所述)。这源于两个线程可以同时获取相反顺序的锁的事实,例如swap(1,2)和swap(2,1)。现在线程1持有locker [1]并等待lockar [2]和线程2另一个wa轮。为避免这种情况,您应该对锁定获取进行排序,例如始终按升序排列。
轻微缺陷: - 不要使x成为实例变量 - 不要将lockedIndex公开(除非真的从外部调用)
关于并发主题的优秀书籍,即使有点过时了: