首先介绍下CountDownLatch,CountDownLatch是一个灵活的闭锁实现,可用于以下三种情况
- 确保一个计算不会执行,直到他需要的资源被初始化
- 确保一个服务不会开始,直到依赖的其他服务都已就绪
- 等待直到活动的所有部分都为继续处理作好准备
CountDownLatch的状态包括一个计数器初始化为一个正数,countDown方法对计数器做减操作,await方法(阻塞)等待计数器达到零,或者线程中断以及超时。
Kafka AbstractServerThread类源码:
private[kafka] abstract class AbstractServerThread(connectionQuotas: ConnectionQuotas) extends Runnable with Logging {
//线程启动的闭锁
private val startupLatch = new CountDownLatch(1)
//线程关闭的闭锁,如果在执行构造函数时抛出异常,shutDown方法将会在该闭锁被countDown前被执行
//如果闭锁初始化为1那么shutDown方法将一直阻塞
//声明为volatile保证可见性
@volatile private var shutdownLatch = new CountDownLatch(0)
private val alive = new AtomicBoolean(true)
def wakeup(): Unit
def shutdown(): Unit = {
if (alive.getAndSet(false))
wakeup()
shutdownLatch.await()
}
//等待该线程启动前所依赖的服务或资源已初始化
def awaitStartup(): Unit = startupLatch.await
//表示该线程启动前所依赖的服务或资源已初始化
protected def startupComplete(): Unit = {
// Replace the open latch with a closed one
shutdownLatch = new CountDownLatch(1)
startupLatch.countDown()
}
//表示该线程关闭前其他任务已经完成
protected def shutdownComplete(): Unit = shutdownLatch.countDown()
AbstractServerThread类提供了一组方法来帮助实现线程启动和关闭所依赖的事件发生的逻辑,这些方法会在具体的线程启动类中被调用。
Acceptor(AbstractServerThread类的子类)线程创建代码:
val acceptor = new Acceptor(endpoint, sendBufferSize, recvBufferSize, brokerId, connectionQuotas)
addProcessors(acceptor, endpoint, processorsPerListener)
//线程启动
KafkaThread.nonDaemon(s"kafka-socket-acceptor-$listenerName-$securityProtocol-${endpoint.port}", acceptor).start()
//等待启动前的事件发生
acceptor.awaitStartup()
acceptors.put(endpoint, acceptor)
/**
Accepter run方法部分代码
def run() {
serverChannel.register(nioSelector, SelectionKey.OP_ACCEPT)
//启动前的事件已经发生
startupComplete()
*
*
*
}
*/
shutDown方法同理,不再赘述。