Search code examples
javamultithreadingwait

Calling wait() doesn't stop the correct thread


I'm new to multithreading in java. I'm trying to run a program that can simulate multiple "Writers" who would write data as output.

I want the writers to all stop at some point so I'm calling wait() on them, but it's not working. I know where the problem happens but I do not know why it happens.

public void run() {
    ExecutorService executor = Executors.newFixedThreadPool(nbOfWriters);
    try {
        // Create a list with all the writers that should run at the same time
        Writer[] writers = new Writer[nbOfWriters];
        for (int i = 0; i < nbOfWriters; i++) {
            writers[i] = new Writer(i);
            executor.execute(writers[i]);
        }
        /*
        Expected outcome:
        start every writer -> wait 3 seconds
        pause every writer -> wait 3 seconds
        run every writer -> wait 3 seconds
        end
        */
        TimeUnit.SECONDS.sleep(3);
        for (Writer writer : writers) {
            synchronized (writer) {
                System.out.println("HERE 1");
                writer.wait();
                System.out.println("HERE 2");
            }
        }

        TimeUnit.SECONDS.sleep(3);
        for (Writer writer : writers) {
            synchronized (writer) {
                writer.notify();
            }
        }
        Thread.sleep(3);
        // End of the test
        for (Writer writer : writers) writer.end();
    } 
    catch (InterruptedException ex) {
        System.out.println(ex.getMessage());
    }
    finally {
        try {
            executor.shutdown();
            executor.awaitTermination(5, TimeUnit.SECONDS);
        } 
        catch (InterruptedException ex) {
            ex.getMessage();
        }
        finally {
            executor.shutdownNow();
        }
    }
}

The Writers just write stuff as output (not important here). I've added print statement "HERE 1" and "HERE 2" to show where the program fails. Basically "HERE 2" is never reached.

In theory what should happen is that I get data written as output for 3 second, then nothing for 3 seconds, then again data written as output.

The actual output is: Stuff gets written as output for 3 second. "HERE 1" printed. Stuff continues to get displayed as output, no pause, no "HERE 2" and the program never stops.

It seems to me like wait() is stopping the wrong thread.


Solution

  • Shouldn't writer.wait() call wait in the specific writer thread like other methods would?

    No.

    The statement, writer.wait(); uses the writer object as a monitor. A monitor is meant to be used in a very specific way*. It allows one thread to wait for some (possibly unknown) other thread to complete a task. The thread that wants to do the waiting does so by calling o.wait();

    There is no way for one thread to make make another thread call a function. There is no way for one thread to make another thread do anything at all. Threads do what the code they are executing tells them to do, and in a well designed program, that code tells them to cooperate with one another. There are ways for thread A to ask thread B to do something, but it's up to you to write the code that runs in thread A to do the asking, and it's up to you to write the code that runs in thread B that recognizes when it's being asked, and then does whatever thing.


    * See the Oracle "guarded block" tutorial.
    Note! that the tutorial does not use the word "monitor", but it talks about the same pattern.