tryLock上的Java IllegalMonitorStateException

时间:2010-12-29 12:27:51

标签: java locking

我想知道是否有人可以帮助我。我是并发编程的新手,我有以下代码,有时会给我一个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

再次感谢您对我迟到的回复的所有回答和道歉。

3 个答案:

答案 0 :(得分:3)

以下是您的计划的快速解决方法:

  1. 摆脱lock1lock2 字段,它们是你的来源 问题。
  2. 替换所有引用 使用lock1locker[a]lock2 locker[b]tryLock()
  3. 您的程序没有任何死锁问题,因为您使用的是lock(),因此您并不需要担心这一点。如果您使用lock1,那么您需要考虑获取锁定的顺序,否则您可能会死锁(请参阅其他答案)。

    现在您当前程序存在缺陷的原因是因为lock2lock1字段是跨线程共享的。例如,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公开(除非真的从外部调用)

关于并发主题的优秀书籍,即使有点过时了:

http://java.sun.com/docs/books/cp/