how to unit test a synchronized method?

19,338

Solution 1

You could test this by having multiple threads execute the method and then asserting that the result is what you would expect. I have my doubts about how effective and reliable this would be. Multithreaded code is notoriously difficult to test and it mostly comes down to careful design. I would definitely recommend adding tests that assert that the methods you expect to by synchronized actually have the synchronized modifier. See an example of both approaches below:

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.junit.Test;

public class SyncTest {
  private final static int NUM_THREADS = 10;
  private final static int NUM_ITERATIONS = 1000;

  @Test
  public void testSynchronized() throws InterruptedException {
    // This test will likely perform differently on different platforms.
    ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
    final Counter sync = new Counter();
    final Counter notSync = new Counter();

    for (int i = 0; i < NUM_THREADS; i++) {
      executor.submit(new Runnable() {
        @Override
        public void run() {
          for (int i = 0; i < NUM_ITERATIONS; i++) {
            sync.incSync();
            notSync.inc();
          }
        }
      });
    }

    executor.shutdown();
    executor.awaitTermination(5, TimeUnit.SECONDS);
    assertThat(sync.getValue(), is(NUM_THREADS * NUM_ITERATIONS));
    assertThat(notSync.getValue(), is(not(NUM_THREADS * NUM_ITERATIONS)));
  }

  @Test
  public void methodIncSyncHasSynchronizedModifier() throws Exception {
    Method m = Counter.class.getMethod("incSync");
    assertThat(Modifier.isSynchronized(m.getModifiers()), is(true)); 
  }

  private static class Counter {
    private int value = 0;

    public synchronized void incSync() {
      value++;
    }

    public void inc() {
      value++;
    }

    public int getValue() {
      return value;
    }
  }
}

Solution 2

CandiedOrange is correct in his comment to your question. In other words, and given the method you mentioned, you should not worry about threadA calling the method at the same moment threadB is since both calls are writing to index. Had it been something like:

void incrementIndex() {
     index++;
     System.out.println(index); // threadB might have written to index
                                // before this statement is executed in threadA
}

threaA calls the method, increments index in the first statement, then attempts to read the value of index in the second statement, by which time threadB might have already made the call to the method and incremented index before threadA reads it and prints it. This is where synchronized is necessary to avoid such a situation.

Now, if you still want to test synchronization, and you have access to the method code (or maybe you can do a similar prototype), you may consider something like the following that illustrates how multithreading behaves with synchronized methods:

public void theMethod(long value, String caller) {
    System.out.println("thread" + caller + " is calling...");
    System.out.println("thread" + caller + " is going to sleep...");

    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("thread" + caller + " woke up!");
}

This should output:

threadA is calling...
threadA is going to sleep...
threadA woke up!
threadB is calling...
threadB is going to sleep...
threadB woke up!

Without the synchronized keyword, the output be:

threadA is calling...
threadA is going to sleep...
threadB is calling...
threadB is going to sleep...
threadA woke up!
threadB woke up!
Share:
19,338
elfar
Author by

elfar

Studying computer engineering at University of Tehran.

Updated on July 20, 2022

Comments

  • elfar
    elfar almost 2 years

    Say I have such a method:

    synchronized void incrementIndex() {
          index++;
    }
    

    I want to unit test this method to see whether index's final value is set correctly if multiple threads simultaneously attempt to increment index. Assuming I don't know about the "synchronized" keyword in the method's declaration (and I only know the contract of the method), how can I do the test?

    p.s. I am using Mockito for writing test cases if it helps.