Java concurrency in practice - Listing 14.9 explanation?

Several lists from JCIP have appeared here. Here is another ( source code ):

  public class ThreadGate {
     private boolean isOpen;
     private int generation;

     public synchronized void close () {
         isOpen = false;
     }

     public synchronized void open () {
         ++ generation;
         isOpen = true;
         notifyAll ();
     }

     public synchronized void await () throws InterruptedException {
         int arrivalGeneration = generation;
         while (! isOpen && arrivalGeneration == generation) {
             wait ();
         }
     }
 } 

Comment in the book:

The condition predicate used by expectation is more complicated than just isOpen testing. This is necessary because if N threads are waiting at the gate at the time of its opening, they should be allowed to continue. But if the gate opens and closes with quick succession, all threads may not be released if the wait checks only isOpen: by the time all the threads receive a notification, close the lock again and exit the wait, the gate can be closed again, Thus, ThreadGate uses a slightly more complex predicate of the condition: each time the gate closes, the “generation” counter increases, and the flow can pass if the gate is open now or if the gate has opened, since this thread has reached the gate.
You guys can laugh, but I can’t understand it :). Questions:
  • explain the use of arrivalGeneration == generation for me in terms of threads T1, T2, ... and thread execution.
  • why does the passage say every time the gate is closed, a generation counter is incremented ? How does this happen?

Thanks everyone!

+4
source share
5 answers

For those interested, find the answer here .

In this list, the waiting thread T1 is interested if any open event occurred while waiting (we don’t care if any close events occurred), generation counter helps us find out this fact.

+1
source

question # 1: Just look at the “generation”, since the group to which you (the stream) belongs, whole groups are allowed, so if the door opens, group # grows, and everyone belonging to the group that was already waiting is allowed, even if the door is again considered as “locked”.

question # 2: I suppose this is a mistake - he probably should read "every time the gate opens ..."

+2
source

Question 1:

  while (!isOpen && arrivalGeneration == generation) { wait(); } 

if Thread 1 enters, arrivalGeneration = generation = 1, and then the gate closes. Topic 1 releases the lock, wait (), and then the generation should increase, ++ generations. generation = 2.

when Thread 1 gets a lock again. arrivalGeneration (= 1) dose is not equal to generation (= 2). therefore, Thread 1 does not wait.

Question 2: this means that the door is closed, and then the door is open, so there is an increase in generation.

0
source

I think the key point is "This is necessary, because if N threads are waiting at the gate at the time of its opening , all of them should be allowed to continue .". To do this, it is enough to check only "! IsOpen" when "the gates open and close quickly." We must have a way to find out that the gates open, even if the gates are closed quickly. In the end, N threads in the previous generation are expected to continue.

Question 1. For the first time, when all threads receive a notification, close the lock again and exit wait, arrivalGeneration - 0, and the generation will receive a new value of 1, so N threads can be continued.

Question 2: I think this is also a mistake.

0
source

This is my explanation of using arrivalGeneration == generation :

Streams wait at the gateway until both conditions are met: the gate is closed AND the local arrivalGeneration value in their await() methods is equal to the current generation value.

Why do we need the second condition here?

Suppose the first group (generation) of participating threads is waiting for the gateway to open. Their local arrivalCeneration value is 0 , and the value of the current generation instance is also 0 . When the gate begins to open, the generation value increases by one and is now equal to 1 (so that newcomers now receive the local arrivalGeneration value set to 1 ). Then the notifyAll() gate open method is called. Our waiting streams from group 0 take time to wake up. During this time, the gate can be closed again. However, since the second condition arrivalGeneration == generation now false for group 0, they do not continue iteration in the while loop and are allowed to pass through the gate (even if the first condition is true because the gate is officially closed again).

At the same time, those participants from group No. 1 who were unable to slip through the gate before they closed again go into the while loop to wait, because both conditions are fulfilled for them: the gate is closed and their local arrivalGeneration value is 1 which matches the current generation value. The next time the gate starts to open again, the generation value will be updated to 2 , and the stream from group # 1 will be able to complete their passage through the gate, etc.

0
source

Source: https://habr.com/ru/post/1315613/


All Articles