RocketMQ RMQ_SYS_TRANS_HALF_TOPIC 爆掉的问题

现象

SaaS项目东郭反应,项目中发的事务消息一直在RMQ_SYS_TRANS_HALF_TOPIC中,并且不断增长。随即我们查看RocketMQ日志发现如下情况:

这个本来是RocketMQ正常的逻辑,发送事务消息后没有提交状态的话,当达到超时时间后,RocketMQ会回查本地事务状态。这里显示的是回查的次数超限,消息被移到了TRANS_CHECK_MAXTIME_TOPIC中。

不正常的是REAL_TOPIC变成了RMQ_SYS_TRANS_HALF_TOPIC,正常应该是原始的业务消息TOPIC才对。于是我们带着这个问题开始排查起来。

阅读更多

PriorityQueue解析

本文转载至github:https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/8-PriorityQueue.md

PriorityQueue

总体介绍

前面以Java ArrayDeque为例讲解了StackQueue,其实还有一种特殊的队列叫做PriorityQueue,即优先队列。优先队列的作用是能保证每次取出的元素都是队列中权值最小的(Java的优先队列每次取最小元素,C++的优先队列每次取最大元素)。这里牵涉到了大小关系,元素大小的评判可以通过元素本身的自然顺序(natural ordering),也可以通过构造时传入的比较器Comparator,类似于C++的仿函数)。

阅读更多

深入开源框架底层之ASM

什么是 ASM ?

ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

阅读更多

从字节码来说明i++与++i到底有什么不同

看字节码之前需要先了解相关概念,如栈帧、操作数栈、局部变量表。
栈帧是JVM中很重要的一个概念,因为JVM是基于栈的架构。一个方法的调用其实就是栈帧入栈出栈的过程。栈顶栈帧就是当前方法调用。
一个栈帧中包含:

  1. 局部变量表
  2. 操作数栈
  3. 动态链接
  4. 方法返回地址
阅读更多

AbstractQueuedSynchronizer-随记

常见误区:Lock(乐观锁,自旋锁)一定比Synchronized好。这个说法是不正确的。自旋锁适合锁竞争不是很激烈的情况下使用,因为其使用了死循环,比较消耗CPU资源。Synchronized在JDK1.5后进行了优化,通过锁升级(偏向锁->轻量级锁(通常是自旋)->重量级锁) 提升了性能。

CountDownLatch-注意事项

先看一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

CountDownLatch countDownLatch = new CountDownLatch(params.size());
try {
params.forEach(regionNameMapping -> {
CompletableFuture.runAsync(() -> {
Region region = this.getRegionById(regionNameMapping.getRegionId());
regionNameMapping.getRegionNameConsumer().accept(region.getName());
countDownLatch.countDown();
});
});
countDownLatch.await();
} catch (Exception e) {
log.error(e.getMessage(), e);
}

上面的代码逻辑很简单,并发去执行getRegionById这个方法。然后await等待结果。
但是里面有一个隐患,当region查出来为null时,会出现NPE,就会导致countDown()无法被执行,于是程序就一直阻塞在

1
2

countDownLatch.await();
阅读更多

获取jar中的文件注意事项

获取resources下的文件Java有很多种方法。但是如果你的程序最终打成jar发布。那么需要注意你是否以流inputstream读取。
因为jar中的文件路径为jar!xxxxxx 简单的使用path 或者getResouces肯定获取不到。

为什么阿里禁止通过Executors创建线程池

Executors是通过new一个ThreadPoolExecutor来创建的线程池。来看看ThreadPoolExecutor的构造方法:

1
2
3
4
5
6
7
8
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
阅读更多

对变量加锁后是否还需要使用volatile

大家都知道volatile保证了变量在线程间的可见性(主内存与CPU缓存(线程内存)间)。Lock与synchronized也可以保证可见性,还能保证原子性。
那么使用了Lock与synchronized之后,变量是否就不用加volatile了?

阅读更多