简体   繁体   中英

Can't get notifyAll to work as intended

I have a function inside of a Runnable class A:

public void function1(){
     synchronized(lock){
        function2.decrease();
        lock.notifyAll();
        System.out.print(function2.getValue());
}

I have another function inside of a Runnable class B:

public void function3(){
    try{
        synchronized(lock){
            while(!(function2.getValue() != 0)){
                lock.wait();
            }
            Thread.sleep(1000);
            System.out.println(function2.getValue() + 10);
        }
    }catch(InterruptedException e){
        System.err.println(e);
    }
}

When I run the program it always prints in function1 before it prints in function3 even if the wait condition evaluates to true.

What do I need to do to print the value in function3 before printing the value in function1?

Looks like you're probably running function1 several times to decrement the value of function2 and then do the while loop check in function3. So, first off, it is perfectly normal to expect function1 to print before function3 in this scenario, as function3 waits for 1 second before its print statement while in the meantime function1 can do whatever it wants.

Secondly, perhaps a more elegant solution is to do the check for function2's value inside function1 and then notifyAll() in the case that it is == 0. That way, no while loop is necessary in function3 and it merely uses wait() and waits for a notifyAll() call from function1.

What I mean: Function1 add

if(function2.getValue() == 0)
    lock.notifyAll();

Function3 remove while loop

// no while loop
lock.wait();

Then to answer original question, to ensure function3 prints first inside the if statement in function1 call lock.wait() after notifyAll() and add notifyAll() at end of function3.

Compilable class below that demonstrates.

public class StackSyncProb{
    private volatile int function2;
    private Object lock = new Object();

    public static void main(String[] args){
        StackSyncProb s = new StackSyncProb(3); // function2 starts at 3
        // start function3, which waits
        s.runFunction3();
        // decrement using function1 until hit 0 (in this case, 3 times)
        for(int i = 0; i < 3; i++){
            s.runFunction1();
        }
    }

    public StackSyncProb(int v){
        function2 = v;
    }

    public void runFunction1(){
        new Thread(new Run1()).start();
    }

    public void runFunction3(){
        new Thread(new Run2()).start();
    }

    public class Run1 implements Runnable{
        @Override
        public void run(){
            function1();
        }
        public void function1(){
            try{
            synchronized(lock){
                function2--;
                // Use if statement to check inside function1 instead of in function3
                if(function2 == 0){
                    lock.notifyAll();
                    // After notifying, wait until function3 done
                    lock.wait();
                }
                System.out.println("function1: " + function2);
            }
            }catch(InterruptedException e){}
        }
    }

    public class Run2 implements Runnable{
        @Override
        public void run(){
            function3();
        }
        public void function3(){
            try{
                synchronized(lock){
                    // No while loop
                    lock.wait();
                    Thread.sleep(1000);
                    System.out.println("function3: " + (function2 + 10));
                    // Notify function1 it can complete and print
                    lock.notifyAll();
                }
            }catch(InterruptedException e){
                System.err.println(e);
            }
        }
    }
}

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