最近使用 vert.x 在开发一个 java 程序,只所以用 vert.x 就是因为它比较适合开发这类的程序。但是异步编程开发起来实在不好维护。。实现也太麻烦了,实在是太复杂了。下单完还要判断是否成功,还有循环下单等,很多时候异步实现起来非常的不好实现和阅读。
目前引入的虚拟线程遇到非常大的麻烦。一般一个 verticle 绑定一个 eventloop 线程,我把虚拟线程绑定 vert.x eventloop 的线程中,,这样每个 verticle 内使用的所有虚拟线程也是它们自己平台 eventloop 线程,也就是在 verticle 使用的所有虚拟线程和自己平台线程 都是同一个线程,所以理论也是线程安全的。目前遇到的是虚拟线程和它自己的平台线程在执行 log 日志输出的时候,就会遇到死锁。也就是虚拟线程和它自己的平台线程发生了竞争 log.info 的输出。
Thread Thread[#63,vert.x-eventloop-thread-1,5,main] has been blocked for 10586 ms, time limit is 2000 ms
io.vertx.core.VertxException: Thread blocked
at java.base/jdk.internal.misc.Unsafe.park(Native Method)
at java.base/java.util.concurrent.locks.LockSupport.park(LockSupport.java:221)
at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:754)
at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:990)
at java.base/java.util.concurrent.locks.ReentrantLock$Sync.lock(ReentrantLock.java:153)
at java.base/java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:322)
at ch.qos.logback.core.OutputStreamAppender.writeBytes(OutputStreamAppender.java:200)
at ch.qos.logback.core.OutputStreamAppender.writeOut(OutputStreamAppender.java:193)
at ch.qos.logback.core.OutputStreamAppender.subAppend(OutputStreamAppender.java:228)
at ch.qos.logback.core.OutputStreamAppender.append(OutputStreamAppender.java:102)
at ch.qos.logback.core.UnsynchronizedAppenderBase.doAppend(UnsynchronizedAppenderBase.java:85)
at ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:51)
at ch.qos.logback.classic.Logger.appendLoopOnAppenders(Logger.java:272)
at ch.qos.logback.classic.Logger.callAppenders(Logger.java:259)
at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:426)
使用 jstack -l pid 检查确实一直 block 中.
LockSupport.class
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
try {
if (t.isVirtual()) {
VirtualThreads.park();
} else {
U.park(false, 0L);
}
} finally {
setBlocker(t, null);
}
}
由于 verticle 可能是很多个,可能会绑定到同一个 eventloop 线程,所以很难从代码上比较难规避不使用 eventloop 平台线程 。
一般使用 ReentrantLock.lock 产生死锁的情况是什么原因呢?个人感觉跟 vert.x 关系不大,应该跟虚拟线程的有关系。
目前不确定是否 ReentrantLock.lock 的问题,还是 logback 日志框架的问题。尝试直接用 ReentrantLock.lock 进行测试,额-也没有复现。。。但是用 log.info 打印日志必现。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.