章
目
录
Java面试题:谈谈对Java线程通信方式的理解?
得分点:
Monitor、Condition
标准回答:
在Java中,常用的线程通信方式有两种:基于Monitor(监视器)的线程通信和基于Condition的线程通信。线程通信通常需要建立在线程同步的基础上,因此选择通信方式取决于线程同步的方式。
Monitor(基于synchronized的线程通信)
如果采用synchronized
关键字进行同步,线程通信通常依赖于Monitor,也称为同步监视器。在synchronized
同步模式下,锁对象可以是任意类型,因此通信方法通常定义在Object
类中,包括:
wait()
: 当线程调用wait()
时,它会释放锁并进入等待状态。notify()
: 当其他线程调用notify()
时,会唤醒等待在此锁上的一个线程。notifyAll()
: 当其他线程调用notifyAll()
时,会唤醒等待在此锁上的所有线程。
Condition(基于Lock和Condition的线程通信)
JDK 1.5引入了Lock
接口及其实现类,提供了更灵活的同步方式。如果采用Lock
对象进行同步,线程通信通常依赖于Condition
,Condition
对象是由Lock
对象创建的,它依赖于特定的Lock
对象。Condition
对象中的通信方法类似于Object
类中的方法,包括:
await()
: 当通过Condition
调用await()
时,当前线程会释放锁并进入等待状态。signal()
: 当通过Condition
调用signal()
时,会唤醒等待在此Condition
上的一个线程。signalAll()
: 当通过Condition
调用signalAll()
时,会唤醒等待在此Condition
上的所有线程。
加分回答:
线程同步是基于同步队列实现的,而线程通信是基于等待队列实现的。调用等待方法时,当前线程将被添加到等待队列。调用通知方法时,等待队列中的一个或多个线程将被移动到同步队列。
因为synchronized
通常只有一个Monitor,因此它只有一个等待队列。相比之下,Lock
对象可以创建多个Condition
,因此它可以拥有多个等待队列。多个等待队列提供了更大的灵活性,因此基于Condition
的通信方式更为推荐。
举例来说,在实现生产者-消费者模型时,生产者需要通知消费者,消费者需要通知生产者。避免出现生产者通知生产者或消费者通知消费者的情况非常重要。如果使用synchronized
实现此模型,由于只有一个等待队列,生产者和消费者都将加入同一个队列,可能会导致误通知的问题。而使用Lock
时,可以创建两个Condition
,一个用于生产者,一个用于消费者,以有效地区分它们,避免误通知。这种灵活性使基于Condition
的通信更加可控。