33

The following Function is executing in its own thread:

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

When the execution reaches the line serverAddr.wait(60000) it throws an Exception:

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

Does anyone know how to lock an object or a function in order to prevent the concurrency? I've tried to add a Lock object:

private final Lock lock = new ReentrantLock();

and the line

boolean locked = lock.tryLock();

at the beginning of function but it didn't work.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
Niko Gamulin
  • 66,025
  • 95
  • 221
  • 286

7 Answers7

65

In order to call wait() on an object, you have to hold the synchronized lock on that object (though the lock is actually released while the thread is waiting):

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

I have to admit that why you're wanting to do this baffles me in this case...

Neil Coffey
  • 21,615
  • 7
  • 62
  • 83
  • Sorry, just to be clear: I understand why you have to acquire the lock on the object before waiting on it. What I don't understand is the *logic* of what the original poster is actually trying to do...!!! – Neil Coffey Mar 30 '09 at 19:51
  • 1
    Oh, then my comment is redacted :) – Bill K Mar 30 '09 at 22:51
  • 1
    +1 for "the lock is actually released while thread is waiting", helped me fixed another issue and I wasn't aware of that (yes, am new to java) – spirytus Aug 17 '12 at 02:28
  • I assume the OP is trying to ensure that only one connection to that address is being made at any given time. If that's the case, I predict that it still won't work because each thread sees a different 'serverAddr' object, although I could be wrong on that. – Aquarelle Mar 06 '14 at 08:40
21

Maybe the method you are looking for is Thread.sleep(long)? This method will wait (as in stop the execution of the thread) for the specified time in milliseconds before resuming.

object.wait(long) (which is what you are using) does something entirely different. It waits for another object from another thread to notify it (ie: send it a sort of wakeup message), and will wait at most the specified number of milliseconds. Given the code you posted, I highly doubt this is what you really want.

If Thread.sleep() is not what you want, then you should use the synchronized block as mentioned by the other posters.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
LordOfThePigs
  • 11,050
  • 7
  • 45
  • 69
11

I always cringe when I see this kind of code. Do yourself a favour and have a look at the java.util.concurrent package.

Apocalisp
  • 34,834
  • 8
  • 106
  • 155
1

To avoid that error message, use the synchronized keyword:

synchronized(serverAddr){
  serverAddr.wait(60000);
}
krosenvold
  • 75,535
  • 32
  • 152
  • 208
1

The above are correct. You can use a synchronized block of code. Or you can create what they call a mutex. A mutex can actually be any object. Lots of people just use Object itself as a mutex. Then you can lock on the mutex. Any threads wanting to get access must wait for thread holding the mutex to release it.

There was also a suggestion by Apocalisp. I would also recommend that you look at the java.util.concurrent package.

uriDium
  • 13,110
  • 20
  • 78
  • 138
0

Below code should work.

     private final ReentrantLock lock = new ReentrantLock();

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

Refer to this documentation page for more details.

public void lock()

Acquires the lock.

Acquires the lock if it is not held by another thread and returns immediately, setting the lock hold count to one.

If the current thread already holds the lock then the hold count is incremented by one and the method returns immediately.

If the lock is held by another thread then the current thread becomes disabled for thread scheduling purposes and lies dormant until the lock has been acquired, at which time the lock hold count is set to one

Refer to this SE question to know the advantages of lock over synchronization:

Synchronization vs Lock

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
0

In general when you have multi-threaded program in Java you need to lock the shared variable by using synchronized (key-word) then in anytime just one thread can access the shared memory.