Java monitors: how do I know if wait (long timeout) has timed out or Notify ()?

Firstly, it is almost a duplicate: How to distinguish the output for waiting (long timeout) for notification or timeout?

But this is a new follow-up question.

Availability of this announcement pending:

public final native void wait(long timeout) throws InterruptedException; 

It can exit InterruptedException either with a timeout or because the Notify / NotifyAll method was called in another thread, the exception is easy to catch, but ...

My code absolutely needs to know if the timeout has been exited or notified. (In the future, this code needs to be redesigned, but it cannot be done now. Therefore, I need to know the reason for exiting the wait.)

In particular, can someone point out an example of using ThreadLocal Boolean, which is set to true only upon notification (), and where is all this inside an existing loop, as shown below? (This was a more or less accepted answer in another thread, but no specific code example was provided. I am not so familiar with Java, so I need a specific code example - ideally in the context of the existing code below.)

 public synchronized int getLastSequenceNumber() { while (empty) { try { wait(waitTimeValue); } catch (InterruptedException e) {} } empty = true; return reportedSequenceNumber; } public synchronized void reconcileLastSequenceNumber(int sequenceNumber) { empty = false; this.reportedSequenceNumber = sequenceNumber; notifyAll(); } 

the logical “empty” serves a purpose outside the specific question I ask here. I believe that I will need to add another boolean in order to fulfill the proposed answer from the original question. How would I integrate this proposed solution into the existing code snippet above? Thanks.

+6
source share
4 answers

You might be better off using Condition (and its await ) rather than built-in monitors because await returns a boolean value indicating whether the timeout has expired.

And even then you should beware of a false awakening (which is indistinguishable from calling signal .)

+8
source

In any case, you should use a loop no matter what you are, regardless of whether there was a wait timeout - in part because of the possibility of false awakenings. However, I'm not at all sure that you really need to know if the call came out due to a notification or not.

Consider a situation where a notification occurs a nanosecond before the timeout expires compared to a situation where a notification occurs a nanosecond after a timeout. What is the useful difference between the two? In principle, there is a condition for the race if they occur at "about the same time."

As far as I can tell, wait() really does not allow you to tell if the call has timed out or not, but this should not affect your code. You should go in cycles and test something else that is a side effect of the notification anyway.

I don’t understand where ThreadLocal comes into play, to be honest, it’s exactly the opposite of what you want, if you need to tell from the waiting thread whether the thread notification has reached a certain point. I don't think you need an extra variable at all - your empty is ok.

+3
source

There is no direct way to report this to the monitor’s built-in API, but you can replace wait() and other functions with a new implementation that tracks this explicitly (unchecked):

 private int wait_ct = 0, signal_ct = 0; public void checkedNotifyAll() { synchronized { signal_ct = wait_ct; notifyAll(); } } public void checkedNotify() { synchronized { signal_ct++; if (signal_ct > wait_ct) signal_ct = wait_ct; notify(); } // Returns true if awoken via notify public boolean waitChecked(long timeout, int nanos) throws InterruptedException { synchronized(this) { try { wait_ct++; super.wait(timeout, nanos); if (signal_ct > 0) { signal_ct--; return true; } return false; } finally { wait_ct--; if (signal_ct > wait_ct) signal_ct = wait_ct; notify(); // in case we picked up the notify but also were interrupted } } // Note: Do not combine this with normal wait()s and notify()s; if they pick up the signal themselves // the signal_ct will remain signalled even though the checkedWait()s haven't been // awoken, potentially resulting in incorrect results in the event of a spurious wakeup 

This is not necessarily a good way to do this, of course; if you close the time before notify() is called, the signal condition may be lost in the end. You really have to wait in a loop, checking for some constant conditions.

+1
source

This is an extended version based on the Jenkov signal class. An exception occurs if it does not end with a Notify character. Thought it would help as I ran into the same problem.

 public class MonitorObject{ } public class Signal{ MonitorObject myMonitorObject = new MonitorObject(); boolean wasSignalled = false; public void doWait(int timeOut) throws InterruptedException,TimeoutException{ synchronized(myMonitorObject){ long startTime = System.currentTimeMillis(); long endTime = startTime + timeOut; Log.d(TAG, String.format("MonitorStart time %d",startTime)); while(!wasSignalled){ long waitTime = endTime - System.currentTimeMillis(); if(waitTime > 0) myMonitorObject.wait(waitTime); else{ Log.e(TAG, String.format("Monitor Exit timeout error")); throw new TimeoutException(); } } Log.d(TAG, String.format("MonitorLoop Exit currentTime=%d EndTime=%d",System.currentTimeMillis(),startTime + timeOut)); //Spurious signal so clear signal and continue running. wasSignalled = false; } } public void doNotify(){ synchronized(myMonitorObject){ wasSignalled = true; myMonitorObject.notify(); } } } 
+1
source

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


All Articles