简体   繁体   English

java中的条件变量是什么?

[英]What is a Condition Variable in java?

Q1.一季度。 What is a condVar in Java? Java 中的 condVar 是什么? If I see the code below, does a condition variable necessarily have to be within the ' mutex.acquire() ' and ' mutex.release() ' block?如果我看到下面的代码,条件变量是否一定必须在“ mutex.acquire() ”和“ mutex.release() ”块内?

public void put(Object x) throws InterruptedException {
   mutex.acquire();
   try {
      while (count == array.length)
      notFull.await();
      array[putPtr] = x;
      putPtr = (putPtr + 1) % array.length;
      ++count;
      notEmpty.signal();
  }
  finally {
     mutex.release();
  }
}

I have three threads myThreadA , myThreadB , myThreadC running which call the same function commonActivity() which triggers the function myWorkReport() eg我有三个线程myThreadAmyThreadBmyThreadC运行,它们调用相同的函数commonActivity()触发函数myWorkReport()例如

public void myWorkReport(){
    mutexMyWork.acquire();
    try{
         while(runMyWork){
             doWork();
             conditionMyWork.timedwait(sleepMyWork);
         }
    }
    finally{
       mutexMyWork.release()
    }    
}

public void commonActivity(){
    try{
        conditionMyWork.signal(); 
    }finally{
        //cleanup
    }   
}

public void myThreadA(){
    mutexA.acquire();
    try{
        while(runningA){    //runningA is a boolean variable, this is always true as long as application is running
            conditionA.timedwait(sleepA);
            commonActivity();
        }
    }
    finally{
        mutexA.release();
    }
}


public void myThreadB(){
    mutexB.acquire();
    try{
        while(runningB){    //runningB is a boolean variable, this is always true as long as application is running
            conditionB.timedwait(sleepB);
            commonActivity();
        }
    }
    finally{
        mutexB.release();
    }
}

public void myThreadC(){
    mutexC.acquire();
    try{
        while(runningC){    //runningC is a boolean variable, this is always true as long as application is running.
            conditionC.timedwait(sleepC);
            commonActivity();
        }
    }
    finally{
        mutexC.release();
    }
}

Q2. Q2。 Is using timedwait a good practice.使用 timedwait 是一种很好的做法。 I could have achieved the same by using sleep().我可以通过使用 sleep() 来达到同样的效果。 If using sleep() call is bad, Why?如果使用 sleep() 调用不好,为什么?

Q3. Q3。 Is there any better way to do the above stuff?有没有更好的方法来做上述事情?

Q4.第 4 季度。 Is it mandatory to have condition.signal() for every condition.timedwait(time);是否必须有condition.signal()为每condition.timedwait(时间);

Q1) The best resource for this is probably the JavaDoc for the Condition class. Q1)最好的资源可能是 Condition 类的JavaDoc Condition variables are a mechanism that allow you to test that a particular condition holds true before allowing your method to proceed.条件变量是一种机制,允许您在允许您的方法继续之前测试特定条件是否成立。 In the case of your example there are two conditions, notFull and notEmpty .在您的例子的情况下,有两个条件, notFullnotEmpty

The put method shown in your example waits for the notFull condition to become true before it attempts to add an element into the array, and once the insertion completes it signals the notEmpty condition to wake up any threads blocked waiting to remove an element from the array.您的示例中显示的 put 方法在尝试将元素添加到数组之前等待notFull条件变为真,并且一旦插入完成,它就会向notEmpty条件发出信号以唤醒任何阻塞等待从数组中删除元素的线程.

...does a condition variable necessarily have to be within the 'mutex.acquire()' and 'mutex.release()' block? ...条件变量是否必须位于“mutex.acquire()”和“mutex.release()”块内?

Any calls to change the condition variables do need to be within a synchronized region - this can be through the built in synchronized keyword or one of the synchronizer classes provided by the java.util.concurrent package such as Lock .任何更改条件变量的调用都需要在同步区域内 - 这可以通过内置的synchronized关键字或java.util.concurrent包提供的同步器类之一,例如Lock If you did not synchronize the condition variables there are two possible negative outcomes:如果您没有同步条件变量,则有两种可能的负面结果:

  1. A missed signal - this is where one thread checks a condition and finds it does not hold, but before it blocks another thread comes in, performs some action to cause the condition to become true, and then signals all threads waiting on the condition.错过的信号 - 这是一个线程检查条件并发现它不成立的地方,但在它阻止另一个线程进入之前,执行一些操作以使条件变为真,然后向所有等待该条件的线程发出信号。 Unfortunately the first thread has already checked the condition and will block anyway even though it could actually proceed.不幸的是,第一个线程已经检查了条件并且无论如何都会阻塞,即使它实际上可以继续进行。

  2. The second issue is the usual problem where you can have multiple threads attempting to modify the shared state simultaneously.第二个问题是常见的问题,您可以让多个线程同时尝试修改共享状态。 In the case of your example multiple threads may call put() simultaneously, all of them then check the condition and see that the array is not full and attempt to insert into it, thereby overwriting elements in the array.在您的示例中,多个线程可能同时调用put() ,然后所有线程检查条件并查看数组未满并尝试插入其中,从而覆盖数组中的元素。

Q2) Timed waits can be useful for debugging purposes as they allow you to log information in the event the thread is not woken up via a signal. Q2)定时等待可用于调试目的,因为它们允许您在线程未通过信号唤醒的情况下记录信息。

Using sleep() in place of a timed wait is NOT a good idea, because as mentioned above you need to call the await() method within a synchronized region, and sleep() does not release any held locks, while await() does.使用sleep()代替定时等待不是一个好主意,因为如上所述,您需要在同步区域内调用await()方法,并且sleep()不会释放任何持有的锁,而await()会. This means that any sleeping thread will still hold the lock(s) they have acquired, causing other threads to block unnecessarily.这意味着任何休眠线程仍将持有它们获得的锁,从而导致其他线程不必要地阻塞。

Q4) Technically, no you don't need to call signal() if you're using a timed wait, however, doing so means that all waits will not return until the timeout has elapsed, which is inefficient to say the least. Q4)从技术上讲,不,如果您使用定时等待,则不需要调用signal() ,但是,这样做意味着所有等待都不会在超时过去之前返回,这至少可以说是低效的。

Q1: A Condition object is associated (and acquired from) a Lock (aka mutext) object. Q1:一个Condition对象关联(并从)一个 Lock(又名 mutext)对象。 The javadoc for the class is fairly clear as to its usage and application.该类的 javadoc 对其用法和应用程序相当清楚。 To wait on the condition you need to have acquired the lock, and it is good coding practice to do so in a try/finally block (as you have).要等待您需要获得锁的条件,在 try/finally 块中这样做是一种很好的编码习惯(就像您一样)。 As soon as the thread that has acquired the lock waits on a condition for that lock, the lock is relinquished (atomically).一旦获得锁的线程等待该锁的条件,锁就会被释放(以原子方式)。

Q2: Using timed wait is necessary to insure liveness of your program in case where the condition you are waiting for never occurs. Q2:在您等待的情况永远不会发生的情况下,使用定时等待对于确保程序的活跃性是必要的。 Its definitely a more sophisticated form, and it is entirely useless if you do not check for the fact that you have timed out and take action to handle the time out condition.它绝对是一种更复杂的形式,如果您不检查已超时的事实并采取措施处理超时情况,则它完全没有用。

Using sleep is an acceptable form of waiting for something to occur, but if you are already using a Lock ("mutex") and have a condition variable for that lock, it make NO sense not to use the time wait method of the condition :使用 sleep 是一种可以接受的等待某事发生的形式,但是如果您已经在使用锁(“互斥锁”)并且有该锁的条件变量,那么不使用条件的时间等待方法是没有意义

For example, in your code, you are simply waiting for a given period but you do NOT check to see if condition occurred or if you timed out.例如,在您的代码中,您只是在等待给定的时间,但您不会检查条件是否发生或是否超时。 (That's a bug.) What you should be doing is checking to see if your timed call returned true or false. (这是一个错误。)您应该做的是检查您的定时调用是否返回 true 或 false。 (If it returns false, then it timed out & the condition has NOT occured (yet)). (如果它返回 false,则它超时并且条件尚未发生(尚未))。

public void myThreadA(){
    mutexA.acquire();
    try{
        while(runningA){    //runningA is a boolean variable
            if(conditionA.await (sleepATimeoutNanos))
                commonActivity();
            else {
                // timeout!  anything sensible to do in that case? Put it here ...
            }
        }
    }
    finally{
        mutexA.release();
    }
}

Q3: [edited] The code fragments require a more detailed context to be comprehensible. Q3:[已编辑] 代码片段需要更详细的上下文才能理解。 For example, its not entirely clear if the conditions in the threads are all the same (but am assuming that they are).例如,它不完全清楚线程中的条件是否都相同(但我假设它们是相同的)。

If all you are trying to do is insure commonActivity() is executed only by one thread at a time, AND, certain sections of the commonActivity() do NOT require contention control, AND, you do require the facility to time out on your waits, then, you can simply use a Semaphore .如果您要做的只是确保 commonActivity() 一次仅由一个线程执行,并且 commonActivity() 的某些部分不需要争用控制,并且,您确实需要该设施在等待时超时,然后,您可以简单地使用 Semaphore Note that sempahore has its own set of methods for timed waits .请注意,信号量有自己的一组定时等待方法。

If ALL of the commonActivity() is critical, AND, you really don't mind waiting (without timeouts) simply make commonActivity() a synchronized method.如果所有的 commonActivity() 都是关键的,并且,您真的不介意等待(没有超时),只需将 commonActivity() 设为同步方法即可。

[final edit:)] To be more formal about it, conditions are typically used in scenarios where you have two or more thread co-operating on a task and you require hand offs between the threads. [最终编辑:)] 更正式地说,条件通常用于有两个或多个线程协作处理任务并且需要线程之间切换的场景。

For example, you have a server that is processing asynchronous responses to user requests and the user is waiting for fulfillment of a Future object.例如,您有一个服务器正在处理对用户请求的异步响应,而用户正在等待 Future 对象的实现。 A condition is perfect in this case.在这种情况下,条件是完美的。 The future implementation is waiting for the condition and the server signals its completion.未来的实现正在等待条件,服务器发出完成的信号。

In the old days, we would use wait() and notify(), but that was not a very robust (or trivially safe) mechanism.在过去,我们会使用wait() 和notify(),但这不是一个非常健壮(或非常安全)的机制。 The Lock and Condition objects were designed precisely to address these shortcomings. Lock 和 Condition 对象正是为了解决这些缺点而设计的。

(A good online resource as a starting point ) (一个很好的在线资源作为起点

Buy and read this book .购买并阅读这本书

Q1 . Q1 I believe by "condition variable", you're referring to something you check to determine the condition that you waited on.我相信通过“条件变量”,您指的是您检查以确定您等待的条件的东西。 For example - if you have the typical producer-consumer situation, you might implement it as something like:例如 - 如果您有典型的生产者-消费者情况,您可以将其实现为:

List<T> list;

public T get()
{
    synchronized (list)
    {
         if (list.get(0) == null)
         {
             list.wait();
         }
         return list.get(0);
    }
}

public void put(T obj)
{
    synchronized (list)
    {
         list.add(obj);
         list.notify();
    }
}

However, due to the potential of spurious thread wakeups, it is possible for the consumer method to come out of the wait() call while the list is still empty.但是,由于虚假线程唤醒的可能性,消费者方法可能会在列表仍为空时从wait()调用中退出。 Thus it's good practice to use a condition variable to wait/sleep/etc.因此,使用条件变量来等待/睡眠/等是一种很好的做法。 until the condition is true:直到条件为真:

while (list.get(0) == null)
{
    list.wait();
}

using while instead of if means that the consumer method will only exit that block if it definitely has something to return.使用while不是if意味着消费者方法只会在它肯定有东西要返回时才退出该块。 Broadly speaking, any sleep or wait or blocking call that was triggered by a condition, and where you expect the condition to change, should be in a while block that checks that condition every loop.从广义上讲,任何由条件触发的睡眠或等待或阻塞调用,以及您期望条件改变的地方,都应该在每个循环检查该条件的while块中。

In your situation you're already doing this with the while (count == array.length) wrapper around notFull.await() .在您的情况下,您已经在notFull.await()周围使用while (count == array.length)包装器执行此操作。

Q2 . Q2 Timed wait is generally a good practice - the timeout allows you to periodically perform a sanity check on your environment (eg has a shutdown-type flag been flipped), whereas a non-timed wait can only be stopped by interruption.定时等待通常是一个很好的做法 - 超时允许您定期对您的环境执行健全性检查(例如翻转关闭类型标志),而非定时等待只能通过中断停止。 On the other hand, if the wait is going to just keep blocking anyway until the condition is true, it makes little difference it it wakes up every 50 ms (say) until the notify() happens 2 seconds later, or if it just blocks constantly for those 2 seconds.另一方面,如果等待将一直阻塞直到条件为真,那么它每 50 毫秒唤醒一次(比如)直到notify()发生 2 秒后,或者它只是阻塞持续那 2 秒。

As for wait() vs sleep() - the former is generally preferable, since it means you get woken up as soon as you are able to take action.至于 wait() 与 sleep() - 前者通常更可取,因为这意味着一旦您能够采取行动,您就会被唤醒。 Thread.sleep(500) means that this thread is definitely not doing anything for the next 500ms, even if the thing it's waiting for is ready 2ms later. Thread.sleep(500)意味着该线程在接下来的 500 毫秒内绝对不会做任何事情,即使它等待的事情在 2 毫秒后准备就绪。 obj.wait(500) on the other hand would have been woken up 2ms into its sleep and can continue processing. obj.wait(500)会在 2 毫秒内被唤醒进入睡眠状态并可以继续处理。 Since sleeps introduce unconditional delays in your program, they're generally a clunkier way to do anything - they're only suitable when you're not waiting on any specific condition but actually want to sleep for a given time (eg a cleanup thread that fires every 60 seconds).由于睡眠会在您的程序中引入无条件延迟,因此它们通常是一种更笨拙的做任何事情的方式 - 它们仅适用于您不等待任何特定条件但实际上想要睡眠给定时间的情况(例如,一个清理线程每 60 秒触发一次)。 If you're "sleeping" because you're waiting for some other thread to do something first, use a wait() (or other synchronous technique such as a CountDownLatch ) instead.如果您因为等待其他线程先执行某事而“休眠”,请改用wait() (或其他同步技术,例如CountDownLatch )。

Q3 . Q3 Pass - it looks like there's a lot of boilerplate there, and since the code doesn't have any comments in and you haven't explained what it's supposed to do and how it's meant to behave, I'm not going to try and reverse-engineer that from what you're written.通过 - 看起来那里有很多样板,而且由于代码中没有任何注释,而且您还没有解释它应该做什么以及它的行为方式,我不会尝试反向-从你写的东西中设计出来。 ;-) ;-)

Q1.一季度。 Condition variables are part of monitors facility which is sometimes used for threads synchronization.条件变量是监视器工具的一部分,有时用于线程同步。 I don't recognize this particular implementations but usually conditional variables usage must be done in the critical section, thus mutex.acquire and release are required.我不认识这个特定的实现,但通常条件变量的使用必须在临界区中完成,因此需要mutex.acquirerelease

Q2. Q2。 timedwait waits for signal on condition variable OR time out and then reqcquires critical section. timedwait等待条件变量 OR 超时的信号,然后请求临界区。 So it differs from sleep.所以它与睡眠不同。

Q3. Q3。 I am not sure, but I think you may use built-in monitors functionality in java: synchronized for mutual exclusion and wait and notify instead of cond vars.我不确定,但我认为您可以使用 java 中的内置监视器功能: synchronized用于互斥和waitnotify而不是 cond 变量。 Thus you will reduce dependencies of your code.因此,您将减少代码的依赖性。

Q1.一季度。 I think documentation gives quite good description.我认为文档给出了很好的描述。 And yes, to await or signal you should hold the lock associated with the condition.是的,要awaitsignal您应该持有与条件相关的锁。
Q2. Q2。 timedWait is not in Condition API, it's in TimeUnit API. timedWait不在Condition API 中,它在TimeUnit API 中。 If you use Condition and want to have a timeout for waiting use await(long time, TimeUnit unit) .如果您使用Condition并希望等待超时,请使用await(long time, TimeUnit unit) And having a timeout is generally a good idea - nobody wants a program to hang forever - provided you know what to do if timeout occurs.设置超时通常是一个好主意——没有人希望程序永远挂起——前提是你知道如果超时发生该怎么办。
Sleep is for waiting unconditionally and await is for waiting for an event. Sleep 用于无条件等待,await 用于等待事件。 They have different purposes.他们有不同的目的。 Q3. Q3。 I don't know what this code is expected to do.我不知道这段代码应该做什么。 If you want to perform some action cyclically, with some break between each iteration, use sleep instead of conditions.如果您想循环执行某些操作,在每次迭代之间有一些休息时间,请使用睡眠而不是条件。
Q4.第 4 季度。 As I wrote above conditions don't have timedwait method, they have await method.正如我上面写的,条件没有timedwait方法,它们有await方法。 And calling await means you want to wait for some event to happen.调用await意味着您要等待某个事件发生。 This assumes that sometimes this event does happen and someone signals this.这假设有时此事件确实发生并且有人发出信号。 Right?对?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM