web-dev-qa-db-ja.com

Javaのスレッド:オブジェクトをロックする方法は?

次の関数は、独自のスレッドで実行されています。

_private void doSendData()
{
    try {

           //writeToFile(); // just a temporary location of a call
           InetAddress serverAddr = InetAddress.getByName(serverAddress);
           serverAddr.wait(60000);
           //Log.d("TCP", "C: Connecting...");
           Socket socket = new Socket(serverAddr, portNumber);
           socket.setSoTimeout(3000);

               try {
                //Log.d("TCP", "C: Sending: '" + message + "'");
                PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);
                String message = packData();
                out.println(message);
                Log.d("TCP", "C: Sent.");
                Log.d("TCP", "C: Done.");
                connectionAvailable = true;

             } catch(Exception e) {
                 Log.e("TCP", "S: Error", e);
                 connectionAvailable = false;

               } finally {
                  socket.close();
                  announceNetworkAvailability(connectionAvailable);
                }

         } catch (Exception e) {
              Log.e("TCP", "C: Error", e);
              announceNetworkAvailability(connectionAvailable);
         }
}
_

実行がserverAddr.wait(60000)行に達すると、例外がスローされます。

_Java.lang.IllegalMonitorStateException: object not locked by thread before wait()
_

並行性を防ぐためにオブジェクトまたは関数をロックする方法を知っている人はいますか? Lockオブジェクトを追加しようとしました:

_private final Lock lock = new ReentrantLock();
_

そしてライン

_boolean locked = lock.tryLock();
_

機能の最初でしたが、うまくいきませんでした。

33
Niko Gamulin

オブジェクトでwait()を呼び出すには、そのオブジェクトの同期ロックを保持する必要があります(ただし、スレッドが待機している間に実際にロックが解除されます)。

synchronized (serverAddr) {
  serverAddr.wait();
}

whyこれをやりたいのは、この場合私を困惑させることを認めなければならない...

64
Neil Coffey

たぶんあなたが探しているメソッドは Thread.sleep(long) ?このメソッドは、再開する前にミリ秒単位で指定された時間だけwait(スレッドの実行を停止するように)します。

object.wait(long) (これは使用しているものです)はまったく異なることを行います。別のスレッドからの別のオブジェクトに通知するのを待機し(つまり、一種のウェイクアップメッセージを送信する)、指定されたミリ秒数まで待機します。あなたが投稿したコードを考えると、私はこれがあなたが本当に望むものであると非常に疑います。

Thread.sleep()が望んでいない場合は、他の投稿者が述べた同期ブロックを使用する必要があります。

21
LordOfThePigs

この種のコードを見ると、私はいつもうんざりします。どうぞ、Java.util.concurrentパッケージをご覧ください。

11
Apocalisp

上記は正しいです。コードの同期ブロックを使用できます。または、ミューテックスと呼ばれるものを作成できます。ミューテックスは、実際には任意のオブジェクトにすることができます。多くの人は、オブジェクト自体をミューテックスとして使用しています。その後、ミューテックスをロックできます。アクセスを取得したいスレッドは、mutexを保持しているスレッドがそれを解放するのを待たなければなりません。

Apocalispによる提案もありました。また、Java.util.concurrentパッケージを確認することをお勧めします。

1
uriDium

このエラーメッセージを回避するには、synchronizedキーワードを使用します。

synchronized(serverAddr){
  serverAddr.wait(60000);
}
1
krosenvold

以下のコードが動作するはずです。

     private final ReentrantLock lock = new ReentrantLock();

     lock.lock();  // block until condition holds
     try {
        serverAddr.wait(60000);
     } finally {
       lock.unlock()
     }
   }

詳細については、このドキュメントを参照してください page .

public void lock()

ロックを取得します。

ロックが別のスレッドによって保持されていない場合、ロックを取得してすぐに戻り、ロック保持カウントを1に設定します。

現在のスレッドがすでにロックを保持している場合、保持カウントは1ずつ増加し、メソッドはすぐに戻ります。

ロックが別のスレッドによって保持されている場合、現在のスレッドはスレッドスケジューリングの目的で無効になり、ロックが取得されるまで休止状態になります。ロックが取得されると、ロック保持カウントが1に設定されます。

lockに対するsynchronizationの利点については、このSEの質問を参照してください。

同期とロック

0
Ravindra babu

一般に、Javaにマルチスレッドプログラムがある場合、同期(キーワード)を使用して共有変数をロックする必要があり、いつでも1つのスレッドのみが共有メモリにアクセスできます。

0
Khash Nejad