Java: Understand wait () function notify () notifyAll ()

5

I am studying Threads Java and its features and I came across a question.

I have the following classes in my program:

public class Main {

    public static void main(String[] args) {

        ThreadB b = new ThreadB();
        b.start();

        synchronized (b) {
            try {
                System.out.println("Waiting for complete b...");
                b.wait();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("Total: " + b.total);
        }
    }
}

ThreadB :

public class ThreadB extends Thread {

    int total;

    @Override
    public void run() {
        synchronized (this) {

            for (int i = 0; i < 200; i++) {
                total += i;
            }

            notify(); //notifyAll();

            while(true) {
                //Do something
            }
        }
    }
}

Running this program I can not get the expected behavior of the notify() command when I add the code snippet below in ThreadB :

 while(true) {
     //Do something
 }

See outputs with and without the quoted passage

WillIhavetowaittofinishThreadBsameMainbeingnotifiedthatthetotalisalreadycalculated?

IsthereanythingthatcanbedonetogettotalwithoutThreadBending?

Beforearrivinghere,Icheckedthis question with a similar subject from another user.

    
asked by anonymous 29.12.2015 / 19:28

2 answers

5

The problem has nothing to do with wait or notify , but with its synchronized blocks.

See, the behavior of synchronized blocks is the guarantee that only one thread at a time is running for a given object.

Well, in this case the while(true) loop in your code causes your thread to remain forever in the synchronized block, causing the notification sent to the main thread never really go into effect.

What you need to learn from all of this is:

  

Synced blocks should contain as little code as possible

In other words, everything you run within synchronized blocks, even though it is thread-safe , blocks the rest of the program and can often become a bottleneck. In addition, synchronized blocks can lead to deadlocks if badly structured.

Summary:

  

Avoid synchronization wherever possible

    
30.12.2015 / 00:27
3

Although I found the answer enough, I found your question interesting and wanted to complement it with a practical example - since you have practical, as well as theoretical, needs.

A great advantage of using the Java language is its vast standard API, so one advice is to go to the competition documentation and find out what the Java API already provides: docs .

I've already gone ahead and made a functional prototype of your code:

Main.java

public class Main {

    public static void main(String[] args) {
        Future<Integer> future = Executors.newSingleThreadExecutor().submit(new CallableB());

        int total = -1;

        try {
            System.out.println("Waiting for complete b...");
            total = future.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("Total: " + total);
    }
}

CallableB.java (an improvement of ThreadB)

public class CallableB implements Callable<Integer> {

    private int total = -1;

    public CallableB() {
        // executa o runnable
        Executors.newSingleThreadExecutor().execute(new RunnableB());
    }

    @Override
    public Integer call() throws Exception {
        if (total == -1) {
            synchronized (this) {
                wait();
            }
        }

        return mTotal;
    }

    private class RunnableB implements Runnable {

        @Override
        public void run() {
            int tmp = 0;

            for (int i = 0; i < 200; i++) {
                tmp += i;
            }

            total = tmp;

            synchronized (CallableB.this) {
                CallableB.this.notifyAll();
            }

            while(true) {
                //Do something
            }
        }
    }
}

In class Main , I call the class CallabelB through Future .

In class CallabelB implements the Callable interface. which provides a Runnable with a return. In it I evoke RunnableB which is the same implementation of ThreadB , however I use the artifice of the inner class that can access the members of the class where it is contained.

To manage competition, I use both your initial approach to wait() and notifyAll() , and to check the modification of the total variable.

As RunnableB does not have a stop condition, its program never ends, even though the last line of the main method is executed.

Then also take a look at ExecutorService .

I hope I have helped you.

Note: CallableB.this is the mechanism to access the this instance of class CallableB in RunnableB .

    
30.12.2015 / 03:35