[concurrency-interest] Nested synchronized

Howard Lovatt howard.lovatt at gmail.com
Thu Jan 5 19:52:45 EST 2012


Hi,

I have seen something I think is a JVM bug but would like to check my
understanding before reporting a problem. The following program normally
hangs, i.e. the problem is intermittent, on my computer, MacBook Pro, Java
6 or 7, 4 core processor. The problem is that there are synchronized
methods, isSetA1 and isSetA2 (near end of listing below), that call another
synchronized method, conditionallySumArguments (at end of listing below).
The second synchronized is unnecessary since the method is always called
within an already synchronized method and if the second synchronized is
removed the program works as expected. However I think an extra
synchronized should be redundant, not a problem?

package nestedsynchronizedproblem;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import static java.lang.System.*;

/**
 * Test of nested synchronized. Mimics calling a parallel sum method.
 *
 * @author  Howard Lovatt
 */
public class NestedSynchronizedProblem {
  private static final int loops = 10 * 1000 * 1000; // This needs to be
large for hanging!

  public static void main( final String... notUsed ) throws
InterruptedException {
    final ParrallelSumMethod sum = new ParrallelSumMethod();
    final Callable<Void> setA1 = new Callable<Void>() {
      @Override public Void call() throws Exception {
        for ( int l = 0; l < loops; l++ ) { sum.setA1( l ); }
        return null;
      }
    };
    final Callable<Void> setA2 = new Callable<Void>() {
      @Override public Void call() throws Exception {
        for ( int l = 0; l < loops; l++ ) { sum.setA2( l ); }
        return null;
      }
    };
    final ExecutorService pool = Executors.newCachedThreadPool();
    pool.submit( setA1 );
    pool.submit( setA2 );
    pool.shutdown();
    final boolean ok = pool.awaitTermination( 1, TimeUnit.MINUTES );
    out.println( sum.getSum() + (ok ? ", terminated ok" : ", failed to
terminate") );
    pool.shutdownNow();
  }
}


final class ParrallelSumMethod {
  private long sum = 0;
  private Long a1 = null;
  private Long a2 = null;

  public void setA1( final long a1Arg ) throws InterruptedException {
    for ( ;; ) {
      if ( isSetA1( a1Arg ) ) { return; }
      checkForInterrupt();
    }
  }

  public void setA2( final long a2Arg ) throws InterruptedException {
    for ( ;; ) {
      if ( isSetA2( a2Arg ) ) { return; }
      checkForInterrupt();
    }
  }

  public Long getSum() { return sum; }

  private static void checkForInterrupt() throws InterruptedException {
    if ( Thread.interrupted() ) { throw new InterruptedException(); }
  }

  private synchronized boolean isSetA1( final long a1Arg ) {
    if ( a1 == null ) {
      a1 = a1Arg;
      conditionallySumArguments();
      return true;
    }
    return false;
  }

  private synchronized boolean isSetA2( final long a2Arg ) {
    if ( a2 == null ) {
      a2 = a2Arg;
      conditionallySumArguments();
      return true;
    }
    return false;
  }

  private synchronized void conditionallySumArguments() { // Works if not
synchronized!!!
    if ( ( a1 == null ) || ( a2 == null ) ) { return; }
    sum += a1 + a2;
    a1 = a2 = null;
  }
}


Thanks in advance for any comments,

  -- Howard.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20120106/225253d1/attachment-0001.html>


More information about the Concurrency-interest mailing list