BlockingQueue应用

BlockingQueue使用

  def startServer(bindAddress: String, port: Int): Unit = {
    val bootstraps: java.util.List[TransportServerBootstrap] =
      if (securityManager.isAuthenticationEnabled()) {
        java.util.Arrays.asList(new AuthServerBootstrap(transportConf, securityManager))
      } else {
        java.util.Collections.emptyList()
      }
    server = transportContext.createServer(bindAddress, port, bootstraps)
    dispatcher.registerRpcEndpoint(
      RpcEndpointVerifier.NAME, new RpcEndpointVerifier(this, dispatcher))
  }

在Spark中的Master或者Worker启动的时候会创建RpcEnv,启动server之后会调用dispatcher.registerRpcEndpoint方法。

 def registerRpcEndpoint(name: String, endpoint: RpcEndpoint): NettyRpcEndpointRef = {
    val addr = RpcEndpointAddress(nettyEnv.address, name)
    val endpointRef = new NettyRpcEndpointRef(nettyEnv.conf, addr, nettyEnv)
    synchronized {
      if (stopped) {
        throw new IllegalStateException("RpcEnv has been stopped")
      }
      if (endpoints.putIfAbsent(name, new EndpointData(name, endpoint, endpointRef)) != null) {
        throw new IllegalArgumentException(s"There is already an RpcEndpoint called $name")
      }
      val data = endpoints.get(name)
      endpointRefs.put(data.endpoint, data.ref)
      receivers.offer(data)  // for the OnStart message
    }
    endpointRef
  }

在这个方法中,会调用receiver.offer(data)方法。receiver就是一个阻塞队列。

  // Track the receivers whose inboxes may contain messages.
  private val receivers = new LinkedBlockingQueue[EndpointData]

一旦receivers中有数据,立即唤醒MessageLoop线程进行数据的异步处理。

  /** Message loop used for dispatching messages. */
  private class MessageLoop extends Runnable {
    override def run(): Unit = {
      try {
        while (true) {
          try {
            val data = receivers.take()
            if (data == PoisonPill) {
              // Put PoisonPill back so that other MessageLoops can see it.
              receivers.offer(PoisonPill)
              return
            }
            data.inbox.process(Dispatcher.this)
          } catch {
            case NonFatal(e) => logError(e.getMessage, e)
          }
        }

java.util.concurrent.LinkedBlockingQueue#take方法调用,如果队列中没有任何数据,那么将会将线程无限期挂起,直到有队列中添加了数据。
在这里插入图片描述
而Inbox初始化的时候就会向messages中添加OnStart。

  // OnStart should be the first message to process
  inbox.synchronized {
    messages.add(OnStart)
  }

所以服务启动就会执行endponti的start方法。
在这里插入图片描述
从以上的案例,可以看出,阻塞队列有两个重要方法,一个是offer,一个是take,offer就是往队列中加入数据,take则是取数据,如果取不到则先挂起,直到有数据。接下来分析,为啥没有数据,take方法将无限挂起。而offer方法又是如何唤醒挂起线程的。
在这里插入图片描述
最终会调用在这里插入图片描述

LockSupport.unpark方法唤醒线程。

接下来看下take是如何阻塞线程的。
在这里插入图片描述
最终调用了 LockSupport.park(this);
方法,阻塞当前线程。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值