1、问题发现
虽说,synchronized 关键字万能的,在并发上去之后,这个插入就显得很慢了。仔细观察发现,其实锁的粒度还是再细点,可以根据AlarmRules对象的ID来锁。
2、解决过程
很明显synchronized(rules) 这个写法是有问题的。是基于对象的引用作为锁,只有在rules实例相同的情况下。我们实际情况实例不同,id相同的情况。
查询相关资料。进行相关测试 采用
ConcurrentHashMap(线程安全map) + ReentrantLock(可重入的锁)
public class MainTest {
public static void main(String[] args) {
for (int i = 1; i < 20; i++) {
AlarmRules temp = new AlarmRules();
temp.setId(i % 4);
new Thread(new Test(temp)).start();
}
System.out.println("for end");
}
}
Runnable
public class Test implements Runnable {
private AlarmRules bean;
public Test(AlarmRules bean){
this.bean = bean;
}
@Override
public void run() {
SynchTest.synchMethod(bean);
}
}
method
public class SynchTest {
private static final Map<Integer, ReentrantLock> LOCK_MAP = new ConcurrentHashMap<>();
public static void synchMethod(AlarmRules bean){
ReentrantLock lock = LOCK_MAP.computeIfAbsent(bean.getId(), k -> new ReentrantLock());
lock.lock();
try {
System.out.println("bean.getId() = " + bean.getId()+" bean selectOne");
Thread.sleep(2000);
System.out.println("bean.getId() = " + bean.getId()+" bean insert");
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
效果实现。id不同的完美并发执行。提高了方法的效率。
注意
因我有用 CountDownLatch,在latch.await(); 清理资源
LOCK_MAP.remove(rules.getId()); 避免OOM