1.信号量(Semaphore)
信号量通常用于保护数量有限的资源,例如数据库服务器。在资源数量固定的任何情况下,都应该使用有界信号量。在生成任何工作线程前,应该在主线程中初始化信号量。
信号量提供acquire方法和release方法,每当调用acquire方法的时候,如果内部计数器大于0,则将其减1,如果内部计数器等于0,则会阻塞该线程,知道有线程调用release方法将内部计数器更新到大于1位置。
信号量也是一把锁,用来控制线程并发数。信号量通过一个内置的计数器,当加锁时,该数-1,释放时该数+1。计数器不能小于0,当计数器为0时,加锁操作会让线程进入阻塞状态,直到其他线程释放锁之后计数器有空位子。
BoundedSemaphore与Semaphore的唯一区别在于前者将调用release()时检查计数器的值是否超过了初始值,如果超过了将抛出一个异常。
2.条件变量(Condition)
有了互斥锁,为什么还需要条件变量?那是因为对于有些复杂问题,互斥锁搞不定。
所谓条件变量(Condition),即这种机制是在满足了特定的条件后,线程才可以访问相关的数据。条件变量就相当于一个加了条件判断的锁,Condition通常与一个锁相关联。
由Condition类来完成,除了可以像锁机制那样用,有acquire方法和release方法以外,它还有wait,notify,notifyAll方法。
相关方法:
- acquire:加线程锁,调用关联的锁的相应方法。
- release:释放线程锁。
- wait([timeout]):线程挂起(阻塞),使线程进入Condition的等待池等待通知,并释放锁。直到一个notify通知或者超时才会被唤醒继续运行(超时参数默认不设置,可选填,浮点数,单位秒)。在使用前线程必须已获得锁定,否则将抛出异常。
- notify(n=1):从等待池挑选一个线程并通知,收到通知的线程将自动调用acquire()尝试获得锁定(进入锁定池);其他线程仍然在等待池中。调用这个方法不会释放锁定。在使用前线程必须已获得锁定,否则将抛出异常。
- notifyAll():通知等待池中的所有线程,这些线程都将进入锁定池,并尝试获得锁定。调用这个方法不会释放锁定。在使用前线程时必须已获得锁定,否则将抛出异常。
注意:线程条件变量Condition中所有相关函数使用必须在acquire/release内部操作。