Why does my synchronized code block seem to ignore another, waiting synchronized block on the same object?

StackOverflow https://stackoverflow.com/questions/21105869

Question

I am rather puzzled about the behavior of synchronized code blocks in Java. There is one behavior I'm observing that I just don't get. Consider the following code (I'm going to reuse the code example from another question I asked here, as the structure is the same):

class Outer {
    private Object lock;
    private Foo foo;        

    public Outer() {
        lock = new Object();

        // The thread is actually started in an Android callback method,
        // but I'll start it here as a demonstration
        InnerThread thread = new InnerThread(lock);
        thread.setRunning(true);
        thread.start();
    }

    private void modifyFoo() {
        synchronized(lock) {
            Log.d("outer", "outer method");
            foo.bar();    // Has some effect on foo
        }
    }

    private class InnerThread extends Thread {

        private volatile boolean running = false;
        private Object lock;

        public InnerThread(Object lock) {
            this.lock = lock;
        }

        private void setRunning(boolean running) {
            this.running = running;
        }

        @Override
        public void run() {
            while(running) {
                // There is some timer management code here.
                // It executes on the order of microseconds.

                synchronized(lock) {
                    Log.d("thread", "loop");
                    foo.blah();    // Modifies foo
                    // Imagine some time intensive (milliseconds)
                    // drawing method calls here
                }
            }
        }

    }
}

This approach may appear convoluted; just be aware that I adapted this from one of the Android sample applications, and this question isn't about redesigning the structure of my code, unless that is necessary to fix the issue. Just bear in mind that the while loop in the thread is a drawing loop, and that my game logic sometimes comes in and calls the modifyFoo method (Android SDK users may recognize this as a modification to the LunarLander example). The call to modifyFoo looks like this:

Log.d("activity", "calling modifyFoo");
modifyFoo();

The unexpected behavior is shown in the log output when I call the method. I expect something like this:

thread: loop
thread: loop
thread: loop < `modifyFoo` method called during this loop iteration
activity: called modifyFoo
outer: outer method
thread: loop
thread: loop

But I see results more like this (EDIT: Copied actual log with timestamps):

01-23 04:34:28.303: D/thread(399): loop
01-23 04:34:28.335: D/thread(399): loop
01-23 04:34:28.350: D/activity(399): calling modifyFoo
01-23 04:34:28.366: D/thread(399): loop
01-23 04:34:28.381: D/thread(399): loop
01-23 04:34:28.413: D/thread(399): loop
01-23 04:34:28.428: D/outer(399): outer method
01-23 04:34:28.436: D/thread(399): loop
01-23 04:34:28.460: D/thread(399): loop

Note that adding additional log statements at the beginning and end of the synchronized block in the loop confirms that the modifyFoo method is being called while this block is executing.

The space (number of thread loop iterations) between the call to modifyFoo and the service can be extremely long, but sometimes, the delay is so short that it is unnoticeable (it seems, in effect, random). It exhibits itself as a frozen UI, as the outer method runs on my UI thread. Obviously, that's a problem. Inserting a 1ms Thread.sleep(1) outside of the synchronous block in the thread loop seems to fix the problem, so my initial thought was "oh, the synchronous block in the while loop is not giving external threads enough time to call the modifyFoo method". However, based on some logging, it does not appear that modifyFoo always executes during this delay, which is what I'd have expected.

So the question is: what is going on here? Once the outside UI thread is waiting at the synchronized block in modifyFoo, why does the inner thread get back ahold of the lock before modifyFoo makes it "out of the wings"? Cannot synchronized blocks "self queue"?

Was it helpful?

Solution

Whenever any synchronized completes it's execution it notifies to all the other threads waiting for the lock on the same object by saying.

"I am releasing the lock on this object any one of you can start execution."

Now the choice of which thread will be given the lock is random.(I would say unknown).

In your example:

lets say thread loop is executing and modifyFoo method is called.

The thread which is running modifyFoo will wait until lock is released now the moment lock is released because of the while loop another thread is put into wait for lock on the same object and any one of them is picked. now your modifyFoo is still waiting until this loop finishes and same thing happens again.

So after a few executions of thread loop(which will be random) modify foo gets and opportunity to execute.

OTHER TIPS

The thing to remember here is that once a thread blocks waiting for a critical section to become free, it's then up to the scheduler to decide when to yield, and without any other code telling the other threads how to behave, such as wait() or notify(), the scheduler isn't obligated to "be nice", pardon the pun. See Difference between Synchronized block with wait/notify and without them?

Back in the day of of pre-Java 1.5, using synchronized/wait/notify was necessary, but in modern code with the java.util.concurrency package, it's recommended to use the following paradigm for concurrency in order to make locking errors less likely and avoid deadlock or starvation: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top