How to synchronize code based on boolean value?

Viewed 238

I have this code:

    private volatile boolean immortal;
    private Object lock = new Object();
    
    public void set(boolean immortal) {
        this.immortal = immortal;
    }

    public void kill() {
       // .... contains some other code. 
       synchronized(lock) {
            if (!immortal) {
               for (int i = 0; i < numThreads; i++) {
                   runnableList.add(POISON_PILL);
               }
            }
       }
    }

My use case is that I would like the if statement in the kill method to run to completion before immortal value is changed. Is there a better way of doing this without locking on an object?

I mean what is the best way to synchronize a block only if the value of a boolean variable is false and not allow the boolean value to be changed till it runs to completion? Can I achieve this using AtomicBoolean?

2 Answers

A neat way to do this could be to declare your runnableList as a synchronized list:

// where T is whatever type it needs to be
List<T> runnableList = Collections.synchronizedList(new ArrayList<>());

Then you could add to it without explicit synchronization:

if (!immortal) {
  runnableList.addAll(Collections.nCopies(numThreads, POISON_PILL));
}

This works because a single call to addAll is atomic.

This isn't doing it without synchronization, though, it's just internal to the list.


With this said, it's hard to recommend a "better" solution because it's not clear what the requirements are. Synchronization (etc) is used to preserve the invariants of your object when operated on by multiple threads.

For example, why do you need immortal to remain unchanged while you add things to runnableList? How else do you access immortal and runnableList? etc

Use two locks:

private boolean immortal;
private final Object killMonitor = new Object();
private final Object flagMonitor = new Object();

public void set(boolean immortal) {
    synchronized (flagMonitor) {
        this.immortal = immortal;
    }
}

public void kill() {
    // ...
    synchronized (flagMonitor) {
        if (!immortal) {
            synchronized (killMonitor) {
                runnableList.addAll(Collections.nCopies(numThreads, POISON_PILL));
            }
        }
    }
}
Related