kafka客户端--wakeup方法

wakeup 方法

生产端的send方法和消费端都有wakeup方法,其作用是将nio的poll方法中断,(nio poll方法中, waittime为-1表示永久阻塞,0表示立即返回)

生产端唤醒分析:

它的作用就是将 Sender 线程从poll方法的阻塞中唤醒,poll方法的作用是轮询注册在多路复用器上的 Channel,它会一直阻塞在这个方法上,除非满足下面条件中的一个:

  • at least one channel is selected;
  • this selector’s {@link #wakeup wakeup} method is invoked;
  • the current thread is interrupted;
  • the given timeout period expires.

否则 poll 将会一直轮询,阻塞在这个地方,直到条件满足。

分析到这里,KafkaProducer 中 dosend() 方法调用 sender.wakeup() 方法作用就很明显的,作用就是:当有新的 RecordBatch 创建后,旧的 RecordBatch 就可以发送了(或者此时有 Metadata 请求需要发送),如果线程阻塞在 select() 方法中,就将其唤醒,Sender 重新开始运行 run() 方法,在这个方法中,旧的 RecordBatch (或相应的 Metadata 请求)将会被选中,进而可以及时将这些请求发送出去。

消费端consumer.wakeup()方法

消费端一般是使用while(true)无限循环拉取消息, 如果确定要退出循环,需要通过另一个线程调用 consumer.wakeup()方法。如果循环运行 在主线程里,可以在 ShutdownHook里调用该方法。要记住, consumer.wakeup() 是消费者 唯一一个可以从其他线程里安全调用的方法。调用 consumer.wakeup()可以退出 poll(), 并抛出 WakeupException异常,或者如果调用 cconsumer.wakeup() 时线程没有等待轮询, 那 么异常将在下一轮调用 poll()时抛出。我们不需要处理 WakeupException,因为它只是用于跳出循环的一种方式。不过, 在退出线程之前调用 consumer.close()是很有必要的, 它 会提交任何还没有提交的东西 , 并向群组协调器(broker)发送消息,告知自己要离开群组,接下来 就会触发再均衡 ,而不需要等待会话超时。

maybeTriggerWakeup 方法

这个方法就是为了安全的唤醒消费者客户端。注意:并不是在这里唤醒,这里是判断是否有唤醒的风险。
这里维护了两个原子标志(线程安全):

wakeupDisabled: 线程在执行不可中断的方法
wakeup: 线程中断请求
get() 方法是判断值是否为0,非0返回 True
当wakeupDisabled 为 0 并且 wakeup 是 1,即线程没有在执行不可中断的方法,并收到了中断请求,则把 wakeup置为 0 并抛出异常,中断该线程。

    public void maybeTriggerWakeup() {
        if (!wakeupDisabled.get() && wakeup.get()) {
            log.debug("Raising WakeupException in response to user wakeup");
            wakeup.set(false);
            throw new WakeupException();
        }
    }

消费端的唤醒, 有两个地方, 一个是外层无限循环拉取过程中唤醒退出循环, 一个是唤醒NIO的poll阻塞 

发布了544 篇原创文章 · 获赞 633 · 访问量 116万+

猜你喜欢

转载自blog.csdn.net/asdfsadfasdfsa/article/details/105017191