0

I observe following situation:

  • Thread_1 acquires lock on sync object, do some work
  • While Thread_1 hogging lock, Thread_2 tries to acquire same lock, got stuck on synchronized
  • Thread_1 releases lock, do something relatively quickly (without yielding or sleeping), then acquire same lock again
  • Thread_2 remains in waiting state (of cause if scheduler do not switch to Thread_2 in this short period of time when sync object is free to tackle)

The question is: is it possible to do "honest" locking, i.e. grant lock acquiring in order requested it?

Code of test:

public class HonestMutexTest {
  private Object mSync = new Object();
  private Object mSleep = new Object();

  private void sleep(long millis) {
    try {
      Thread.sleep(millis);
    }
    catch (InterruptedException e) {
      Assert.fail();
    }
  }

  private void normalMutexesTestIteration() {
    final StringBuilder states = new StringBuilder();
    final Thread firstThread = new Thread(new Runnable() {
      @Override
      public void run() {
        synchronized (mSync) { // 1
          sleep(100);
          states.append('1');
        }
        synchronized (mSync) {
          states.append('2');
        }
      }
    });
    final Thread secondThread = new Thread(new Runnable() {
      @Override
      public void run() {
        sleep(50);
        synchronized (mSync) { // 2
          states.append('3');
        }
      }
    });
    firstThread.start();
    secondThread.start();
    try {
      firstThread.join(1000);
      secondThread.join(1000);
    }
    catch (InterruptedException e) {
      Assert.fail();
    }
    Assert.assertEquals(states.toString(), "123"); // what I expect here is "132"
  }

  @Test
  public void testNormalMutexes() {
    for (int i = 0; i < 10; ++i) {
      normalMutexesTestIteration();
    }
  }
}
Andrey Starodubtsev
  • 5,139
  • 3
  • 32
  • 46
  • 1
    Would you consider using a multi-threaded, thread-safe, queue? Blocking Deque springs to mind. – vikingsteve Jan 06 '16 at 16:47
  • 4
    http://stackoverflow.com/questions/1802830/ensure-java-synchonized-locks-are-taken-in-order asks a similar question and points users to ReEntrantLock with fair=true. Looking at the docs for ReEntrant lock though it actually just says 'favors' those that have been waiting longer so it's not a sure thing. – Paul Rubel Jan 06 '16 at 16:49
  • @vikingsteve, alas, blocking queue will make algorithm sufficiently more difficult, but as last resort would do the trick, thanks. – Andrey Starodubtsev Jan 06 '16 at 16:53
  • @PaulRubel, ReentrantLock looked promising... until I read your own comment about absense of strict guarantee of locking order =). – Andrey Starodubtsev Jan 06 '16 at 16:57
  • Semaphore actually guarantees fairness, and a semaphore with count 1 could be used as a lock. But maybe they do the same thing as ReentrantLock does, only the descriptions are different? Because I see no reason for this difference in practice. – Sergei Tachenov Jan 06 '16 at 16:58
  • _...While Thread_1 hogging lock.._, there's the problem right there. If lock implementations don't put much emphasis on fairness and priorities and other sophisitcated features, it's probably because your time is better spent designing your code so that the synchronized blocks are all as small as possible instead of trying to figure out ways to deal with lock-hogging threads. – Solomon Slow Jan 06 '16 at 17:57
  • @jameslarge, locking frame is already pretty small, but it wraps access to 3rd-party thread-unsafe component. I can't make it even narrower. Anyway, it seems like I have to rewrite this piece indeed, I just tried to find way to do as less changes as possible. – Andrey Starodubtsev Jan 06 '16 at 18:07

0 Answers0