- 这个waitStrategy的最终用途是创建SequenceBarrier的时候,传给SequenceBarrier做成员变量:
- 在看看SequenceBarrier是如何使用waitStrategy的,一共两处用到,第一处如下图红框,原来是waitFor方法内部会用到,这个waitFor咱们前面已经了解过,对消费者来说,等待环形队列的指定位置有可用数据时,就是调用SequenceBarrier的waitFor完成的:
- SequenceBarrier第二处用到waitStrategy是唤醒的时候:
@Override
public void alert()
{
alerted = true;
waitStrategy.signalAllWhenBlocking();
}
- 现在咱们知道了WaitStrategy的使用场景,接下来看看这个接口有哪些具体实现吧,这样咱们在编程中就知道如何选择才最适合自己
BlockingWaitStrategy
- 作为默认的等待策略,BlockingWaitStrategy还有个特点就是代码量小(不到百行),很容易理解,其实就是用ReentrantLock+Condition来实现等待和唤醒操作的,如下图红框:
- 如果您更倾向于节省CPU资源,对高吞吐量和低延时的要求相对低一些,那么BlockingWaitStrategy就适合您了;
BusySpinWaitStrategy(慎用)
- 前面的BlockingWaitStrategy有个特点,就是一旦环形队列指定位置来了数据,由于线程是等待状态(底层调用了native的UNSAFE.park方法),因此还要唤醒后才能执行业务逻辑,在一些场景中希望数据一到就尽快消费,此时BusySpinWaitStrategy就很合适了,代码太简单,全部贴出:
public final class BusySpinWaitStrategy implements WaitStrategy
{
@Override
public long waitFor(
final long sequence, Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier)
throws AlertException, InterruptedException
{
long availableSequence;
while ((availableSequence = dependentSequence.get()) < sequence)
{
barrier.checkAlert();
ThreadHints.onSpinWait();
}
return availableSequence;
}
@Override
public void signalAllWhenBlocking()
{
}
}
- 上述代码显示,整个while循环的关键就是ThreadHints.onSpinWait做了什么,源码如下,这里要格外注意,如果ON_SPIN_WAIT_METHOD_HANDLE为空,意味着外面的while循环是个非常消耗CPU的自旋:
public static void onSpinWait()
{
if (null != ON_SPIN_WAIT_METHOD_HANDLE)
{
try
{
ON_SPIN_WAIT_METHOD_HANDLE.invokeExact();
}
catch (final Throwable ignore)
{
}
}
}
- ON_SPIN_WAIT_METHOD_HANDLE为空是很可怕的事情,咱们来看看它是何方神圣?代码还是在ThreadHints.java中,如下所示,真相一目了然,它就是Thread类的onSpinWait方法,如果Thread类没有onSpinWait方法,那么使用BusySpinWaitStrategy作为等待策略就有很高的代价了,环形队列里没有数据时消费线程会执行自旋,很耗费CPU:
static
{
final MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle methodHandle = null;
try
{
methodHandle = lookup.findStatic(Thread.class, “onSpinWait”, methodType(void.class));
}
catch (final Exception ignore)
{
}
ON_SPIN_WAIT_METHOD_HANDLE = methodHandle;
}
-
好吧,还剩两个问题:Thread类有没有onSpinWait方法还不能确定吗?这个onSpinWait方法是何方神圣?
-
去看JDK官方文档,如下图,原来这方法是从JDK9才有的,所以对于JDK8使用者来说来说,选用BusySpinWaitStrategy就意味着要面对没做啥事儿的while循环了:
- 第二个问题,onSpinWait方法干了些啥?前面的官方文档,以欣宸的英语水平显然是无法理解的,去看stackoverflow吧,如下图,简单的说,就是告诉CPU当前线程处于循环查询的状态,CPU得知后就会调度更多CPU资源给其他线程:
-
至此真像大白:环形队列的条件就绪后,BusySpinWaitStrategy策略是通过whlie死循环来做到快速响应的,如果JDK是9或者更高版本,这个死循环带来的CPU损耗由Thread.onSpinWait帮助缓解,如果JDK版本低于9,这里就是个简单的while死循环,至于这种死循环有多消耗CPU,您可以写段简单代码感受一下…
-
难怪Disruptor源码中会提醒最好是将使用此实例的线程绑定到指定CPU核:
DummyWaitStrategy
固定返回0,个人觉得这个策略在正常开发中用不上,因为环形队列可用位置始终是0的话,不论是生产还是消费都难以实现:
LiteBlockingWaitStrategy
- 看名字,LiteBlockingWaitStrategy是BlockingWaitStrategy策略的轻量级实现,在锁没有竞争的时候(例如独立消费的场景),会省略掉唤醒操作,不过如下图红框所示,作者说他没有充分验证过正确性,因此建议只用于体验,太好了,这个策略我不学了!!!
TimeoutBlockingWaitStrategy
- 顾名思义,TimeoutBlockingWaitStrategy表示只等待某段时长,超过了就算超时,其代码和BlockingWaitStrategy类似,只是等待的时候有个时长限制,如下图,一目了然:
- 其实我对抛出异常后的处理很感兴趣,去看看吧,外面是熟悉的BatchEventProcessor类,熟悉的processEvents方法,如下图,每次超时异常都交给notifyTimeout处理,而外部的主流程不受影响,依旧不断的从环形队列中等待和获取数据:
- 进入notifyTImeout方法,可见实际上是交给成员变量timeoutHandler去处理的,而且处理过程中发生的任何异常都会被捕获,不会抛出去影响外部调用:
- 再来看看成员变量是哪来的,如下图,真相大白,咱们开发的EventHandler实现类,如果也实现了Timeouthandler,就被当做成员变量timeoutHandler了:
- 至此TimeoutBlockingWaitStrategy也搞清楚了:用于有时间限制的场景,每次等待超时后都会调用业务定制的超时处理逻辑,这个逻辑写到EventHandler实现类中,这个实现类要实现Timeouthandler接口
LiteTimeoutBlockingWaitStrategy
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
最后
关于面试刷题也是有方法可言的,建议最好是按照专题来进行,然后由基础到高级,由浅入深来,效果会更好。当然,这些内容我也全部整理在一份pdf文档内,分成了以下几大专题:
- Java基础部分
- 算法与编程
- 数据库部分
- 流行的框架与新技术(Spring+SpringCloud+SpringCloudAlibaba)
这份面试文档当然不止这些内容,实际上像JVM、设计模式、ZK、MQ、数据结构等其他部分的面试内容均有涉及,因为文章篇幅,就不全部在这里阐述了。
作为一名程序员,阶段性的学习是必不可少的,而且需要保持一定的持续性,这次在这个阶段内,我对一些重点的知识点进行了系统的复习,一方面巩固了自己的基础,另一方面也提升了自己的知识广度和深度。
mg-UHvSbgym-1711656989949)]
- 流行的框架与新技术(Spring+SpringCloud+SpringCloudAlibaba)
[外链图片转存中…(img-LL2vFqT8-1711656989950)]
这份面试文档当然不止这些内容,实际上像JVM、设计模式、ZK、MQ、数据结构等其他部分的面试内容均有涉及,因为文章篇幅,就不全部在这里阐述了。
作为一名程序员,阶段性的学习是必不可少的,而且需要保持一定的持续性,这次在这个阶段内,我对一些重点的知识点进行了系统的复习,一方面巩固了自己的基础,另一方面也提升了自己的知识广度和深度。