问题产生背景
消息队列处理交易信息,交易中包好多个订单,消息是发送的订单数据,可能存在同时处理一个交易的问题
最简单的解决方法是对交易id加锁
测试
测试代码如下,模式10个线程处理交易id相同的消息
OrderMessage o1 = new OrderMessage();
o1.setTid(123L);
OrderMessage o2 = new OrderMessage();
o2.setTid(123L);
final int[] sum = {0};
for (int i = 0; i < 10; i++) {
new Thread(() -> {
synchronized (o1.getTid()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
sum[0]++;
System.out.println(sum[0]);
}
}).start();
new Thread(() -> {
synchronized (o2.getTid()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
sum[0]++;
System.out.println(sum[0]);
}
}).start();
}
Thread.sleep(100000);
输出结果为20 并没有出现线程安全问题
当tid>128 时,问题来了
sum结果为16,明显已经线程不安全了
OrderMessage o1 = new OrderMessage();
o1.setTid(1235L);
OrderMessage o2 = new OrderMessage();
o2.setTid(1235L);
解决方法
采用string intern方法
package com.xqcrm.tb.tbtmc;
import com.xqcrm.tb.tbtmc.common.SysInternPool;
import com.xqcrm.tb.tbtmc.sms.message.OrderMessage;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author huanxi
* @date 2020/9/2 4:44 下午
* @email 1355473748@qq.com
*/
public class MainTest {
public static void main(String[] args) throws InterruptedException {
OrderMessage o1 = new OrderMessage();
o1.setTid(1235L);
OrderMessage o2 = new OrderMessage();
o2.setTid(1235L);
final int[] sum = {0};
for (int i = 0; i < 10; i++) {
new Thread(() -> {
synchronized (SysInternPool.INSTANCE.internTid(o1.getTid())) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
sum[0]++;
System.out.println(sum[0]);
}
}).start();
new Thread(() -> {
synchronized (SysInternPool.INSTANCE.internTid(o1.getTid())) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
sum[0]++;
System.out.println(sum[0]);
}
}).start();
}
Thread.sleep(100000);
}
}
package com.xqcrm.tb.tbtmc.common;
import com.google.common.collect.Interner;
import com.google.common.collect.Interners;
/**
* @author huanxi
* @date 2020/9/2 4:40 下午
* @email 1355473748@qq.com
*/
public enum SysInternPool {
/**
* 实例
*/
INSTANCE;
private Interner<String> pool = Interners.newWeakInterner();
public String internLong(String key, Long id) {
return this.pool.intern(key + id);
}
public String internTid(Long id) {
return this.pool.intern("tid:" + id);
}
}