Question

I'm having a problem with implementing the Synchronized interface on a Java 7 application. I think the problem may be in the fact that I'm instantiating multiple objects with a static final array that is written to in the synchronized method. It appears that the threads are not acknowledging the monitor? Can I even do what I'm trying to do, or do I need some kind of buffer object that has the array and writeIndex incrementer? (If it helps, the code is at https://github.com/dschaper/CS112_Dan_Schaper/tree/master/Week14/Labs and this is not homework, this is just a non-graded lab.)

public class SingleDice extends Dice implements Runnable {
    String threadName;
    private static final int[] valuesArray = new int[9];
    private static int writeIndex = 0;

    public SingleDice(String tName) {
        super(1);
        threadName = tName;
    }

    public synchronized void add(int value) {
        int pos = writeIndex;
        System.out.printf("%s starting sync add(%d), writeIndex = %d\n",
            Thread.currentThread().getName(), value,
            writeIndex);
        valuesArray[pos] = value;
        System.out.printf("%s wrote %d to index %d\n",        
            Thread.currentThread().getName(), value, writeIndex);
        ++writeIndex;
        System.out.printf("Next writeIndex %d\n", writeIndex);
    }
    @Override
    public void run() {
    for (int i = 0; i < 3; i++) {
        add(super.Throw());
        }
    }
}

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

public class SyncDiceExecutor {

public static void main(String[] args) {
    System.out.println("Creating newCachedThreadPool");
    SingleDice SD1 = new SingleDice("SD1");
    SingleDice SD2 = new SingleDice("SD2");
    SingleDice SD3 = new SingleDice("SD3");
    ExecutorService executor = Executors.newCachedThreadPool();
    executor.execute(SD1);
    System.out.printf("Starting Thread SD1 %s\n", executor.toString());
    executor.execute(SD2);
    System.out.printf("Starting Thread SD2 %s\n", executor.toString());
    executor.execute(SD3);
    System.out.printf("Starting Thread SD3 %s\n", executor.toString());
    executor.shutdown();
    System.out.printf("Execeutor shutdown called: %s\n", executor.toString());

    }
}

Output

Creating newCachedThreadPool
Starting Thread SD1 java.util.concurrent.ThreadPoolExecutor@544ec1[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]
pool-1-thread-1 starting sync add(4), writeIndex = 0
pool-1-thread-2 starting sync add(4), writeIndex = 0
Starting Thread SD2 java.util.concurrent.ThreadPoolExecutor@544ec1[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0]
pool-1-thread-2 wrote 4 to index 0
pool-1-thread-1 wrote 4 to index 0
pool-1-thread-3 starting sync add(4), writeIndex = 1
Next writeIndex 1
pool-1-thread-2 starting sync add(6), writeIndex = 2
Starting Thread SD3 java.util.concurrent.ThreadPoolExecutor@544ec1[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
pool-1-thread-2 wrote 6 to index 2
Next writeIndex 3
pool-1-thread-3 wrote 4 to index 2
Next writeIndex 4
Next writeIndex 2
pool-1-thread-3 starting sync add(1), writeIndex = 4
pool-1-thread-2 starting sync add(6), writeIndex = 3
Execeutor shutdown called: java.util.concurrent.ThreadPoolExecutor@544ec1[Shutting down, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
pool-1-thread-2 wrote 6 to index 4
Next writeIndex 5
pool-1-thread-3 wrote 1 to index 4
Next writeIndex 6
pool-1-thread-1 starting sync add(3), writeIndex = 4
pool-1-thread-3 starting sync add(1), writeIndex = 6
pool-1-thread-1 wrote 3 to index 6
pool-1-thread-3 wrote 1 to index 6
Next writeIndex 8
Next writeIndex 7
pool-1-thread-1 starting sync add(1), writeIndex = 8
pool-1-thread-1 wrote 1 to index 8
Next writeIndex 9

Process finished with exit code 0
Was it helpful?

Solution

SD1, SD2 and SD3 are different objects, i.e. they don't share the same monitor. Each object has its own monitor. You could use synchronized(SingleDice.class) {...} if you want to share the monitor across all instances.

OTHER TIPS

The synchronized on non-static method synchronizes on this, so if you have different objects, they are not mutually exclusive. If you can't use static method (which synchronizes on the class), the solution is to add static lock object and synchronize on that to protect static data.

static final Object valueArrayLock = new Object();

...

// inside a method
synchronized(valueArrayLock) {
    // operate on valueArray
}

Note, that if you need to lock this in static methods, use the same static lock object, instead of making the static method synchronized (or see the other answer about using the class object for locking).

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