synchronized不能锁住Integer

今天写了一行代码,觉得完事大吉,结果在真正执行的时候发现无法实现对qId的串行操作,当时就懵逼了。

原始代码:

public JsonResponse synVerifying(Integer qId, BigDecimal score, FanyaUserDetail user, Map<String, String> map) {
    //相同的qId会排序
    synchronized (qId) {
        try {
            //判断是否因网络延迟而造成的单题重复点击,针对同一个用户
            boolean verified = questionVerifyService.isVerified(qId, user.getUid());
            if (verified) {
                Integer counts = questionVerifyService.getCountByQid(qId);
                //不同用户同时审核同一道题时,审核次数大于3,则不用审核了
                if (counts >= 3) {
                    return JsonResponse.failure().put("failMsg", "该题已审核完毕");
                } else {
                    verifyService.verifying(user.getUid(), qId, score, map.get("realName"), map.get("orgName"), counts);
                    return new JsonResponse(JsonResponse.CODE_SUCCESS, "ok");
                }
            } else {
                return JsonResponse.failure().put("failMsg", "请勿重复点击");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResponse.failure().put("failMsg", e.getMessage());
        }
    }
}

修改后代码:

public JsonResponse synVerifying(Integer qId, BigDecimal score, FanyaUserDetail user, Map<String, String> map) {
    //相同的qId会排序
    synchronized (qId.toString().intern()) {
        try {
            //判断是否因网络延迟而造成的单题重复点击,针对同一个用户
            boolean verified = questionVerifyService.isVerified(qId, user.getUid());
            Thread.sleep(5000);
            System.out.println("----------------------");
            System.out.println(verified);
            System.out.println("=======================");
            if (verified) {
                Integer counts = questionVerifyService.getCountByQid(qId);
                //不同用户同时审核同一道题时,审核次数大于3,则不用审核了
                if (counts >= 3) {
                    return JsonResponse.failure().put("failMsg", "该题已审核完毕");
                } else {
                    verifyService.verifying(user.getUid(), qId, score, map.get("realName"), map.get("orgName"), counts);
                    return new JsonResponse(JsonResponse.CODE_SUCCESS, "ok");
                }
            } else {
                return JsonResponse.failure().put("failMsg", "请勿重复点击");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResponse.failure().put("failMsg", e.getMessage());
        }
    }
}

        查了很多资料,发现原来由于Integer的自动装箱和拆箱在作怪。当数据>=127时,就不会放到常量池,而是从新new一个对象。

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

        而使用String.intern()方法就是判断常量池中是否有该数据,有就返回该字符串。

intern

public String intern()
返回字符串对象的规范化表示形式。

一个初始为空的字符串池,它由类 String 私有地维护。

当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。

它遵循以下规则:对于任意两个字符串 st,当且仅当 s.equals(t)true 时,s.intern() == t.intern() 才为 true

所有字面值字符串和字符串赋值常量表达式都使用 intern 方法进行操作。字符串字面值在 Java Language Specification 的 §3.10.5 定义。

返回:
一个字符串,内容与此字符串相同,但一定取自具有唯一字符串的池。

        注意:这里锁住的qId其实是一个对象,所以synchronized锁住的不是字段,而是对象。而要保证相同的值是同一个对象,因此要放入常量池中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值