*解决并发问题的关键在于找到一把共同的锁:
将锁声明为static 保存多个线程访问到同一把锁,把业务中要用到的参数进行加锁获取,保证每次拿到都是最新值,controller是单例和多例都没关系,最好还是用多例,但是锁必须为静态属性,如何是单例,可以是普通属性和静态属性都行,只要保证锁的唯一性就行。
下面附带测试案例,自己根据业务需求灵活运用:
加微信 aa544731152 交流你们遇到的并发问题,随时帮你们解决
@Controller
@RequestMapping("/kan")
@Scope(value="singleton")
public class KanBarginController extends BaseClass{
private static ReentrantLock lock = new ReentrantLock();
/**
* 点击砍价的接口
*/
@RequestMapping(value = "/helpBargain")
@ResponseBody
public JSONObject helpBargain(final ModelMap model,HttpServletRequest request, HttpServletResponse response) {
JSONObject res = new JSONObject();
RedisImpl redis =new RedisImpl();
String orderId = request.getParameter("orderId");
String appId = "wx855d106b81a13845";
String helpPersonOpenId =request.getParameter("helpPersonOpenId");
Map map = productBargainService.queryZyzsFansInfo(helpPersonOpenId);
if(map == null) {
redis.delKey(orderId);
res.put("code", "0001");
res.put("msg","关注后才可帮助好友砍价奥~");
return res;
}
//帮忙砍价人的openId
Map<String,Object> record = productBargainService.queryOrderAndTask(orderId);
//发起人的openId
try {
lock.lock();
Kan kan = redis.getObj(orderId, Kan.class);
if(null == kan) {
redis.delKey(orderId);
res.put("code", "0001");
res.put("msg","已砍到最低价,不能再砍了!");
return res;
}
//1.自己不可以自己砍价
if(kan.getOpenId().equals(helpPersonOpenId)){
res.put("code", "0001");
res.put("msg","自己不能帮自己砍价");
return res;
}
//2.查询是否砍过
Map hasBargain=productBargainService.queryCopyHelper(helpPersonOpenId, orderId);
if(hasBargain!=null){
res.put("code", "0001");
res.put("msg","已经砍过");
return res;
}
if(kan.getNum()==0){
redis.delKey(orderId);
res.put("code", "0001");
res.put("msg","砍价人数已达上线~");
return res;
}
BigDecimal coin = randoncoin(new BigDecimal(kan.getNum()),kan.getLeftmoney(), kan.getMinCoin());
kan.setLeftmoney(kan.getLeftmoney().subtract(coin));
kan.setNum(kan.getNum()-1);
redis.setObj(orderId, kan, 3600*24);
res = productBargainService.help(coin,orderId,helpPersonOpenId);
} catch (Exception e) {
}finally{
lock.unlock();
}
return res;
}
/**
* 随机砍价算法
*/
public BigDecimal randoncoin(BigDecimal num , BigDecimal leftmoney,BigDecimal minCoin){
lock.lock();
BigDecimal money=new BigDecimal(0);
try {
if(num.intValue() == 1) {
return leftmoney;
}
BigDecimal max = leftmoney.divide(num,2, BigDecimal.ROUND_HALF_DOWN).multiply(new BigDecimal(2));
Double next= Math.random() * max.intValue();
money = new BigDecimal(next).divide(new BigDecimal(1),2, BigDecimal.ROUND_HALF_DOWN);
money = money.compareTo(minCoin)<0 ? minCoin : money;
return money;
} catch (Exception e) {
// TODO: handle exception
}finally{
lock.unlock();
}
return money;
}
}
测试案例
public static void test01(){
ExecutorService service = Executors.newCachedThreadPool();
final CountDownLatch latch = new CountDownLatch(2);
for(int i=0;i<2;i++){
final int j = i;
Runnable runnable = new Runnable(){
public void run(){
try {
String url = "http://127.0.0.1/zyzsSd/kan/helpBargain";
String param="";
if(j%2==0){
param="orderId=40284e8166c7c8870166c7cc8ebe0000&helpPersonOpenId="+j;
}else{
param="orderId=40284e8166c7c8870166c7cc8ebe0000&helpPersonOpenId="+j;
}
System.out.println(HttpUtil.sendGet(url, param));
latch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
try {
latch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
service.shutdown();
}