项目中总是出现招标项目超投的情况,最开始总是觉得应该使用框架Hibernate自带的并发策略中的乐观锁(version)解决问题,参考了很多网上的资料,也参考了Hibernate的帮助文档,由于对Hibernate乐观锁机制不了解,问题就一直没有解决。
最近在看Java并发编程相关知识,了解了些许并发,线程,锁的知识。想到了这个问题,曾经使用Synchroized关键字时总是苦于无法获取同一个对象,导致解决方案无效。这次采用的方案是:创建了静态的HashMap,初始化一定数量的对象(可结合服务器的性能来确认对象的数量),采用公平模式竞争锁,在处理业务数据。packagecom;
importjava.util.HashMap;
importjava.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;
publicclasstestMain{
/**
*test类
*@paramargs
*/
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
testOuttestOut=newtestOut();
outPuto=newoutPut(testOut);
//模拟并发三个线程
newThread(o,"first").start();
newThread(o,"second").start();
newThread(o,"thread").start();
}
}
/**
*线程类
*@authorlinyan
*
*/
classoutPutimplementsRunnable{
privatetestOuttestOut;
publicoutPut(testOutt){
testOut=t;
}
@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
testOut.sysout(20);
}
}
/**
*业务处理方法
*@authorlinyan
*
*/
classtestOut{
/**
*创建静态map
*初始化map对象
*/
publicfinalstaticHashMapmap=newHashMap();
static{
for(inti=0;i<2;i++){
//初始化公平锁,确保等待时间最久的线程获得锁
map.put(i,newReentrantLock(true));
}
}
privateintnumber=0;
publicvoidsysout(inti){
System.out.println(Thread.currentThread().getName()+":"+i);
//模拟同一个招标项目的标的编号来争抢锁
intindex=i%map.size();
try{
map.get(index).lock();
//TOOD业务逻辑处理方法
number=number+i;
//输出当前获得线程的锁及请求参数
System.out.println(Thread.currentThread().getName()+":"+index);
//获得当前线程内查看到的活动线程数
System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().activeCount());
//输出对应累加的数值
System.out.println(Thread.currentThread().getName()+"="+number);
}finally{
map.get(index).unlock();
}
}
publicintgetNumber(){
returnnumber;
}
publicvoidsetNumber(intnumber){
this.number=number;
}
}
对应的输出结果:thread:20
first:20
first:0
first:4
first=20
second:20
thread:0
thread:3
thread=40
second:0
second:2
second=60
经过反复的测试,输出的结果都和预期一致,故判定这一解决方案有效。将解决方案放到具体项目上实施,结果仍然出现了超投问题,经过问题定位发现,在业务逻辑处理中业务逻辑的事务分割范围太宽,导致了数据不能立即入库,同时Hibernate的查询仍与缓存交互,不是实时查询数据库,导致继续超投的情况。
事务范围切割问题很好解决,但是对Hibernate查询问题一直没有解决,为了解决问题,采用了临时方案:创建JDBC连接来实时查询。最终以牺牲了部分性能为代价,解决这个问题,最近在研究一下Hibernate查询方式,看是否能用Hibernate的实时查询。