什么是java中的条件变量?

pan*_*ajt 6 java multithreading

Q1.什么是Java中的condVar?如果我看到下面的代码,条件变量是否必须在' 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();
  }
}
Run Code Online (Sandbox Code Playgroud)

我有三个线程myThreadA,myThreadB,myThreadC运行,调用相同的函数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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Q2.使用timedwait是一个很好的做法.我可以通过使用sleep()实现相同的目标.如果使用sleep()调用不好,为什么?

Q3.有没有更好的方法来做上述事情?

Q4.是否必须有condition.signal()为每condition.timedwait(时间);

Jar*_*ell 6

Q1)最好的资源可能是Condition类的JavaDoc.条件变量是一种机制,允许您在允许方法继续之前测试特定条件是否成立.在您的示例中,有两个条件,notFullnotEmpty.

示例中显示的put方法在notFull尝试将元素添加到数组之前等待条件变为true,并且一旦插入完成,它就会发出notEmpty条件以唤醒任何被阻塞的线程,等待从数组中删除元素.

...条件变量是否必须在'mutex.acquire()'和'mutex.release()'块中?

任何更改条件变量的调用都需要在同步区域内 - 这可以通过内置synchronized关键字或java.util.concurrent包提供的其中一个同步器类(如Lock)来实现.如果您没有同步条件变量,则有两种可能的负面结果:

  1. 丢失信号 - 这是一个线程检查条件并发现它不成立的地方,但在它阻塞另一个线程进入之前,执行一些操作以使条件变为真,然后发出信号等待条件的所有线程.不幸的是,第一个线程已经检查了条件,并且无论如何都会阻塞,即使它实际上可以继续.

  2. 第二个问题是通常的问题,您可以让多个线程同时尝试修改共享状态.在您的示例的情况下,多个线程可以put()同时调用,然后所有线程都检查条件并看到数组未满并尝试插入其中,从而覆盖数组中的元素.

Q2)定时等待对于调试目的非常有用,因为它们允许您在线程未通过信号唤醒的情况下记录信息.

使用sleep()代替定时等待不是一个好主意,因为如上所述,您需要await() 在同步区域内调用该方法,并且sleep()不会释放任何保持锁定await().这意味着任何休眠线程仍将保持它们已获取的锁定,从而导致其他线程不必要地阻塞.

Q4)从技术上讲,signal()如果您正在使用定时等待,则不需要调用,但这样做意味着所有等待都不会在超时结束后返回,这至少是低效率的.