简体   繁体   中英

Why are my threads suddenly stopping in Java?

I am supposed to be using two custom Semaphore classes (binary and counting) to print off letters in an exact sequence. Here is the standard semaphore.

public class Semaphore {

protected int value;

public Semaphore() {
    value = 0;
}

public Semaphore(int initial) {
    value = (initial >=0) ? initial : 0;
}

public synchronized void P() throws InterruptedException {
    while (value==0) {
        wait();
    }
    value--;
}

public synchronized void V() {
    value++;
    notify();
}
}

And here is the binary semaphore:

public class BinarySemaphore extends Semaphore {

public BinarySemaphore(boolean unlocked) {super(unlocked ? 1 : 0);}

public synchronized void P() throws InterruptedException{
    while(value==0) {
        wait();
    }
    value=0;
}

public synchronized void V() {
    value=1;
    notify();
}
}

Here is the main bulk of the code, except for a reason I can't work out why the threads stop after around thirty or so repetitions. Wait isn't called, the criteria for being true are being reached, so why aren't they working? Any help is much appreciated.

        BinarySemaphore binaryWXSemaphore = new BinarySemaphore(false);
        BinarySemaphore binaryYZSemaphore = new BinarySemaphore(false);

        Semaphore countingWSemaphore = new Semaphore();
        Semaphore countingYZSemaphore = new Semaphore();

        Runnable runnableW = () -> {
            while(true) {
                if (binaryWXSemaphore.value == 0 && countingYZSemaphore.value >= countingWSemaphore.value) {
                        binaryWXSemaphore.V();
                        countingWSemaphore.V();
                    System.out.println("W");
                }
            }
        };

        Runnable runnableX = () -> {
            while(true) {
                if (binaryWXSemaphore.value == 1) {
                    try {
                        binaryWXSemaphore.P();
                        System.out.println("X");

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        Runnable runnableY = () -> {
            while(true) {
                if (binaryYZSemaphore.value == 0 && countingWSemaphore.value > countingYZSemaphore.value) {
                        binaryYZSemaphore.V();
                        countingYZSemaphore.V();
                    System.out.println("y");

                }

            }
        };

        Runnable runnableZ = () -> {
            while(true) {
                if (binaryYZSemaphore.value == 1 && countingWSemaphore.value > countingYZSemaphore.value) {
                    try {
                        binaryYZSemaphore.P();
                        countingYZSemaphore.V();
                        System.out.println("z");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        };

As @iggy points out the issue is related to fact that different threads are reading different values of value , because the way you access it isn't thread safe. Some threads may be using an old copy of the value. Making it volatile will mean each thread access reads more consistent value:

protected volatile int value;

Or switch to AtomicInteger which ensures thread consistent change to the int stored in value . You'll also need to replace the assignments using set/get/inc/decrement methods of AtomicInteger :

protected final  AtomicInteger value = new AtomicInteger();
// Then use value.set(0 / 1)
// or value.incrementAndGet / decrementAndGet

Unfortunately, even with the above changes, you may find other issues because value could change in the duration between each Runnable's if statement, and the operations inside those if branches.

Also: replacing notify() by notifyAll() usually gives better multi-thread handling though I don't think this necessarily helps in your example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM