3年java开发竟然还不知道Lambda的这个坑
背景
有朋友反馈zk连接很慢。整理出zk连接的关键逻辑如下:
上面的代码造成第一次调用ClientZkAgent.getInstance的时候,需耗时10s, 这个时间恰好跟semaphore的超时时间相当. 在此期间,整个世界好像停滞了一样。
分析
在本地重现后,通过jstack获得系统停滞期间的线程栈,发现这个时候zookeeper的EventThread有个比较奇怪的现象:
客户端实际上很快就连上了zookeeper并返回后生成了SyncConnected事件,而且EventThread已经在回调Watcher.process方法了,但似乎事件线程就一直hold在上面#_1的位置无法往下走, 同时,lambda表达式变成了ClientZkAgent的一个方法了:lambda$connect$0。
了解了一下Java中lambda的实现方式,事情水落石出了。
简而言之,jvm会把lambda表达式转换成所在类的一个方法lambda${method}${seq}(method为该lambda所在的方法名,例如上面的connect方法),同时通过动态代理生成一个代理类(该代理类实现了lambda表达式所代表的具体接口),在该代理类中调用lambda${method}${seq}。
在上面的例子中,生成的代理类大概如下:
再梳理一下:
业务线程:
1.通过静态方法ClientZkAgent.getInstance()获取实例,第一次访问的时候会触发类ClientZkAgent的装载。
2.装载过程中,装载静态成员instance,这时候会尝试创建一个ClientZkAgent对象。
3.在ClientZkAgent的构造函数中连接zk,并通过CountdownLatch进入阻塞状态。注意这时候类装载还没完成。
4.CountdownLatch超时后完成对象的初始化以及整个类的加载
zk事件线程:
SyncConnected事件触发后,调用ClientZkAgent.lambda$connect$0(event), 试图唤醒业务线程(唤醒逻辑在lambda中)。
然而这时候ClientZkAgent还没加载完,事件线程只能等待类加载流程的结束。
业务线程加载完ClientZkAgent后,事件线程完成事件的处理。
可见,在这个过程中,两个线程相互等待(类似死锁但不是死锁),直至业务线程超时后才化解这个局面。
欢迎大家关注我的公种浩【程序员追风】,文章都会在里面更新,整理的资料也会放在里面。
解决
修改ClientZkAgent的初始化逻辑如下:
最后
欢迎大家一起交流,喜欢文章记得点个赞,感谢支持!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
springboot部署到阿里云,配置https,springboot项目同时支持http和https请求,阿里云配置https
最近在学习springboot,感觉springboot开发后台,提供api接口太方便了。简直是傻瓜式开发,一直都是本地在跑springboot项目。梦想着有一天,项目能在阿里云上跑。只有在阿里云上跑才是真正的java服务器项目。这里就带大家一起把springboot项目部署到阿里云,并且支持https 准备工作 阿里云ecs一个 域名一个(我的是https://30paotui.com) ca证书一份(用来支持https) 本地打包好的springboot项目。我这里用jar不用war ftp客户端一个,用来把jar传到阿里云服务器上,我用的是filezilla客户端,可以百度下载。 一,购买阿里云ecs配置安全组规则 如果不配置安全组规则,我们将没法访问我们阿里云服务器 ,下图中的80/80和443/443必须配置,因为只有这里配置了才能支持http和https访问我们的网站 配置如下,授权对象哪里最好填0.0.0.0/0 二,买域名 至于域名怎么买,我就不啰嗦了,不会的自行百度30paotui.com我买的域名 三,通过filezilla连接阿里云服务器,运行项目 我在我的服务器...
- 下一篇
Docker简易部署步骤
Docker简易部署步骤1:系统部安装docker:root权限 >yum install docker 2:系统部修改配置文件: 配置文件路径:/etc/sysconfig/docker 修改如下参数:参数大小可修改,根据需求和机器硬件 OPTIONS='--selinux-enabled --log-driver=journald --graph=/data/docker/dokcer --storage-opt dm.basesize=20G'3:系统部启动docker服务:root权限 >service docker start 查看启动后信息及版本 >docker version >docker info 若如下图所示,则证明docker安装成功 4:配置管理部镜像导入:sudo权限 ①:download纯净的centos镜像 >sudo docker pull centos ②:导入一个本地的镜像docker.tar包 >sudo docker load < docker.tar 5:查看主机上安装的所有镜像:sudo权限 >...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Windows10,CentOS7,CentOS8安装Nodejs环境
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS关闭SELinux安全模块
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2全家桶,快速入门学习开发网站教程