Java中的线程:如何锁定对象?

时间:2009-03-19 04:29:39

标签: java multithreading concurrency locking

以下函数在其自己的线程中执行:

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();

在功能开始但它没有用。

7 个答案:

答案 0 :(得分:64)

为了在一个对象上调用wait(),你必须在该对象上保持同步锁(虽然在线程等待时实际释放了锁):

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

我必须承认为什么你想要这样做会让我感到困惑...

答案 1 :(得分:21)

也许您正在寻找的方法是Thread.sleep(long)?在恢复之前,此方法将等待(如停止执行线程)指定的时间(以毫秒为单位)。

object.wait(long)(这是你正在使用的)做了一些完全不同的事情。它等待来自另一个线程的另一个对象通知它(即:发送一种唤醒消息),并且最多等待指定的毫秒数。鉴于您发布的代码,我非常怀疑这是您真正想要的。

如果Thread.sleep()不是您想要的,那么您应该使用其他海报中提到的synchronized块。

答案 2 :(得分:11)

当我看到这种代码时,我总是畏缩不前。帮自己一个忙,看看java.util.concurrent包。

答案 3 :(得分:1)

要避免该错误消息,请使用synchronized关键字:

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

答案 4 :(得分:1)

以上是正确的。您可以使用同步的代码块。或者你可以创建他们称之为互斥的东西。互斥体实际上可以是任何对象。很多人只是将Object本身用作互斥体。然后你可以锁定互斥锁。任何想要访问的线程都必须等待持有互斥锁的线程才能释放它。

Apocalisp也提出了一个建议。我还建议您查看java.util.concurrent包。

答案 5 :(得分:0)

通常,当您在Java中使用多线程程序时,您需要使用synchronized(key-word)锁定共享变量,然后在任何时候只需一个线程就可以访问共享内存。

答案 6 :(得分:0)

下面的代码应该可以使用。

     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

请参阅此SE问题,了解lock优于synchronization的优势:

Synchronization vs Lock