How to solve starvation with notify and notifyall?

回眸只為那壹抹淺笑 提交于 2019-12-08 02:02:41

问题


How to solve starvation with notify and notifyall?

If we have 4 threads, waiting to acquire a lock on same obj,and the current thread calls notify()

The JVM will select any one thread. Is it possible that thread which called notify(), can again be picked by JVM, as after calling notify(), it would be also in waiting thread list.

This might lead to starvation problem if one of the thread is invoked more number of times than others, unless there is some mechanism where longest waiting thread is picked up first.

I am assuming here that all threads are of same priority. If thread priorities are different, I think highest priority thread will be picked up when notify()

Also, same issues would crop up with notifyall() I think where we don't know which thread will be picked.


回答1:


If you care which thread gets notified, you are doing something wrong. Whatever the notification requires to be done, any thread that is waiting for a notification must be able to do it. If this logic doesn't apply to your use case, then notify is not appropriate for your use case.

Concern about thread fairness generally indicates poorly-designed code. It's your job to make sure your code only does work you actually want it to do and, if necessary, does the most important work first. You shouldn't be expecting the scheduler to somehow do this. The scheduler's job is to get as much work done as possible, enforcing priorities and fairness between processes. The programmer's job is to write code that does the right work.




回答2:


Basically, the threads are randomly picked from the notify() function or notifiAll() function. What you can do is you can use the ReetrantLock with Fair policy. Fair policy avoid thread starvation.

private final ReentrantLock lock = new ReentrantLock(true);



回答3:


Let's ask what the virtual machine is actually doing. I'm going to look at OpenJDK. After some digging (source code available here) we find that the wait method is implemented by this bit of C++.

JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
  JVMWrapper("JVM_MonitorWait");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  assert(obj->is_instance() || obj->is_array(), "JVM_MonitorWait must apply to an object");
  JavaThreadInObjectWaitState jtiows(thread, ms != 0);
  if (JvmtiExport::should_post_monitor_wait()) {
    JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);
  }
  ObjectSynchronizer::wait(obj, ms, CHECK);
JVM_END

Which we follow down to the following defined for ObjectSynchronizer

void ObjectSynchronizer::waitUninterruptibly (Handle obj, jlong millis, TRAPS) {
  if (UseBiasedLocking) {
    BiasedLocking::revoke_and_rebias(obj, false, THREAD);
    assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
  }
  if (millis < 0) {
    TEVENT (wait - throw IAX) ;
    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
  }
  ObjectSynchronizer::inflate(THREAD, obj()) -> wait(millis, false, THREAD) ;
}

And then to the ObjectMonitor returned by inflate where we find this commend

   // Enter the waiting queue, which is a circular doubly linked list in this case
   // but it could be a priority queue or any data structure.

and some ObjectWaiter code that implements aforementioned doubly linked list.

So what have I learnt? Well, firstly that the Hotspot code isn't actually that difficult to navigate. But more relevant to your question - in (this implementation of the JVM) the wait set is implemented as a queue... so threads are given the lock on a first in first out basis. Which means that if any other threads are waiting on the lock they will get it first.

Of course we should never use that information... as the comment above says the wait list can be implemented however the JVM people want to implement it. The JLS gives no indication of the order in which threads should be notified. But I've learnt something if nobody else has.




回答4:


It is not easy to solve with wait/notify(All) but you can look at ReentrantLock/Condition with fairness set to true. ReentrantLock javadoc. It shouldn't matter which of your threads gets the work though.




回答5:


No, a thread that calls Object.notify must own the lock on the object and notifies threads that previously relinqueshed their locks on that object with a call to Object.wait - the notifying thread can't simultaniously notify and wait.

From the Object.notify JavaDoc:

The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object



来源:https://stackoverflow.com/questions/17063426/how-to-solve-starvation-with-notify-and-notifyall

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!