2010-12-29 8 views
0

誰かが私を助けてくれるのだろうかと思っていました。私は並行プログラミングには新しく、現在ロックを所有していないスレッドがロック解除しようとしているときに、IllegalMonitorStateExceptionを私に与えている次のコードを取得しています。tryLockのJava 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 

私は自己学習/宿題の一部としてこれをやっているそう、あなたの答えありがとうございました。 私はロディアンが提案したものと信じているので、コードを以下に変更しました。私はあなたの提案を正しく解釈してほしいと思います。 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

使用方法の例を教えてください。 – dacwe

+0

「lockedIndex(int a、int b)」というメソッドが何であるかはわかりません。あなたはロックの状態を知りたければ簡単に 'lock1.isLocked()'を実行することができます – Dave

+0

複数のスレッドから 'swap'を使っていますか? – dacwe

答えて

1

私はあなたの問題はあなたが複数のスレッドからswap(.., ..)を呼び出し、メンバー(lock1lock2)の変数が別のスレッドによって設定される可能性があるのでswap(および​​)メソッドはスレッドセーフではないということだと思います - あなたは、いくつかの他のunlockうロックしていないインデックス。あなたがロックを取得できない場合はトリッキーなことができtryLockを使用して


は、あなたは何をしますか?

私が解決した解決策は、説明したフォーラムで説明しました。実行した問題の詳細については、索引をperticular orderでロックしてください。Dining philosophers problemを参照してください。ここで

あなたのコードではなくlock()を使用するように書き直される:

class ShuffleBase { 

    private int[] data; 
    private ReentrantLock[] locker; 

    public ShuffleBase(int[] data) { 

     this.data = data; 

     this.locker = new ReentrantLock[data.length]; 
     for (int x = 0; x < data.length; x++) 
      this.locker[x] = new ReentrantLock(); 
    } 

    public void swap(int a, int b) { 

     // check if we have to do sothing 
     if (a == b) 
      return; 

     // set the order (we want to lock lower indexes first!) 
     if (b < a) { 
      int tmp = b; 
      b = a; 
      a = tmp; 
     } 

     // lock them in sequence (first the lower, then the higher index) 
     locker[a].lock(); 
     locker[b].lock(); 

     // do the swap 
     int tmp = data[b]; 
     data[b] = data[a]; 
     data[a] = tmp; 

     // unlock 
     locker[b].unlock(); 
     locker[a].unlock(); 
    } 

    public void display() { 
     for (int i = 0; i < locker.length; i++) locker[i].lock(); 
     System.out.println("Swapped array: " + Arrays.toString(data)); 
     for (int i = 0; i < locker.length; i++) locker[i].unlock(); 
    } 
} 
1

を私はあなたには、いくつかの並行処理について学ぶために勉強や宿題の一部としてこれをやっていると仮定しますか?そうでない場合は、再設計を検討してください。

これは、私がさらにやりたいことは、複数のスレッドから「スワップ」をランダムに呼び出すことです。そうすれば、インスタンス変数に "lock1"と "lock2"を保持しているので、プログラムはすぐに失敗するでしょう。これらはスレッドローカルではありません。「lockedIndex」とは、他のスレッドがこれらの値を上書きする可能性があるため、最終的にロックを解除するのは予測できません。この変数を削除し、常に「ロッカー[]」にアクセスしてください。これはIllegalMonitorStateのために行う必要があります。

この後、デッドロックが発生します(他のフォーラムで述べたように)。これは、2つのスレッドが同時にスワップ(1,2)とスワップ(2,1)のように逆の順序でロックを取得する可能性があることに起因します。現在、スレッド1はロッカー[1]を保持していて、もう一方のスレッドはlockar [2]とスレッド2を待ちます。これを避けるには、ロックの取得を注文する必要があります(たとえば、常に昇順)。

マイナーな欠陥: - 変数インスタンスxを作らない - (本当に外から呼び出されない限り)lockedIndexを公開することはありません

同時実行のトピックに関する優れた著書、少しでも時代遅れ:

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

+0

rodion - あなたが正しいです。私たちは "tryLock"がデッドロックしないという事実を逃しました。あなたは正確なオブザーバーです...良い答え – mtraut

+1

私はインスタンス変数の修正に同意しますが、これらの修正でデッドロックしないことを指摘したいと思います。ロックが試行されると、両方が取得されないとすぐにロックが解除されます。これは、スレッドAが常にロック2を獲得し、スレッドBがそれぞれがもう一方を試みる前に常にロック1を獲得する、スワップ(2,1)スワップ(1,2)のような競合状態につながる可能性があります。そのため、コードは「最下位のインデックスを最初にロックする」などのメカニズムを追加するまで「正しい」コードではありませんが、デッドロックは発生しません。誰も言及していないと思う最終的なヒントは、取得したのと逆の順序でロックを解除する必要があります。 –

3

あなたのプログラムのための簡単な修正です:

  1. 取得lock1lock2 のフィールドを削除すると、それらは 問題の原因になります。
  2. locker[a]locker[b]lock2lock1へのすべての参照を 交換してください。

tryLock()を使用しているため、プログラムでデッドロックの問題が発生することはありません。実際には心配する必要はありません。 lock()を使用した場合は、ロックを取得する順番を考える必要があります。そうでない場合は、デッドロックする可能性があります(他の回答を参照)。

現在、あなたの現在のプログラムに欠陥がある理由は、lock1lock2フィールドがスレッド間で共有されているためです。そう例えば、スレッド1組lock1locker[0]に、その後即座に別のスレッド2はlocker[99]に設定することにより、lock1を上書きするので、スレッド1は、したがって、スレッド2によって取得されたlocker[99]ロックを参照する起こるlock1のロックを解除しようとするとIllegalStateMonitorException

これはこれをクリアします。