记录在springmvc中锁的使用

1.synchronized关键字的使用

参考:http://t.csdn.cn/fWKgS

2.场景1

在一个Service中有两个方法,method1,method2,实现给两个方法都加锁,但其互不影响,也就是method1方法不能两个线程同时执行,method2方法也不能两个线程同时执行,但mehtod1在执行时method2方法可以执行,method2方法在执行时method1方法可以执行

1.若在方法上加synchronized关键字则不能达到预期效果

synchronized关键字加载方法上相当于对该Service实例对象加锁,而一般来说Service是单例的,此时mehtod1方法和method2方法会互相影响,即method1方法在执行时,不仅不能执行method1方法,method2方法也不能执行。

2.定义一个成员对象Object,使用Object作为锁

可以定义一个成员对象Object,在mehtod2方法中通过方法内使用synchronized代码块方式,指定锁为Object对象,即可达到预期效果,method1可以保持不变,即在方法上使用synchronize关键字。此时相当于method1使用的锁是该Service的实例对象,而method2方法使用的锁是Object对象,两者互不影响。

    //为了演示方便,使用Controller层代码演示,效果同Service层代码
    
    private final Object object = new Object();

    @RequestMapping(value = "/method1", method = RequestMethod.GET)
    public synchronized String method1(){
        System.out.println("method1 wait 10s start...");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("method1 wait 10s end...");
        return "method1 success";
    }

    @RequestMapping(value = "/method2", method = RequestMethod.GET)
    public String method2() {
        synchronized (object){
            System.out.println("method1 wait 5s start...");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("method1 wait 5s end...");

            return "method2 success";
        }
    }

3.可以定义两个Object对象,每个方法使用一个作为锁

这里和第二种方式本质是一样的,只是把mehtod1使用的锁从Service实例对象换为了Object对象,这样同样可以达到预期效果

4.使用Lock对象代替synchronized关键字

定义两个Lock对象,这里使用可重入锁ReentrantLock实现,在每个方法体内使用lock和unlock方法实现加锁,释放锁,原理与第三种方法相同,可以达到预期效果。

3.场景2

Service中有两个方法method3,method4,method3方法执行比较耗时,前端调用此方法会出现超时,且影响用户体验,因此需要定义method4方法,前端请求method4方法,该方法直接返回结果,新起线程执行method3方法,但此时有一个问题,因为前端调用method4方法直接返回了结果,因此无法判断method3方法是否执行完成,因为method3方法不能多个线程同时调用,也就是只有其执行完成才能再次调用,否则会出现业务逻辑出错,因此在调用method4方法时判断method3方法是否正在被执行,若在执行则抛出错误信息。

1.使用Lock对象的tryLock方法 + ThreadPoolTaskExecute的submit方法实现

定义一个Lock对象,在method3开始执行时先尝试获取锁,若获取到锁,则执行业务逻辑,此处使用线程休眠10秒代替耗时的业务逻辑,若没有获取到锁,则直接返回。method4方法在提交完任务后,等待1秒或更短的时间去拿任务执行的结果,若拿到,说明method3方法没有获取到锁,因为若拿到了锁,其业务逻辑需要耗时10秒,在提交任务1秒或更短的时间内不可能拿到执行结果,若没有拿到,说明method3方法拿到了锁,正在执行业务逻辑。因此如果拿到了执行结果,则直接返回页面method3方法正在执行请稍后再操作类似信息,若没有拿到执行结果,则返回页面method3方法开始执行,请稍后类似信息。

下面例子中method4若拿到了任务的执行结果则返回执行结果,若没有拿到则返回null

    //为了演示方便,使用Controller层代码演示,效果同Service层代码
    
    private final Lock lock = new ReentrantLock();

    @Resource(name = "myAsync")
    private ThreadPoolTaskExecutor executor;

    @RequestMapping(value = "/method3", method = RequestMethod.GET)
    public String method3(){
        boolean b = lock.tryLock();
        if(b){
            try {
                System.out.println("method3 wait 10s start...");
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("method3 wait 10s end...");
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
            return "method3 success";
        }else {
            return "method3 no lock...";
        }
    }

    @RequestMapping(value = "/method4", method = RequestMethod.GET)
    public String method4(){
        Future<String> submit = executor.submit(() -> method3());
        String s = null;
        try {
            s = submit.get(1, TimeUnit.SECONDS);
        } catch (Exception e){

        }
        System.out.println(s);
        return s;
    }

4.谷歌浏览器测试时发现的问题

当使用谷歌浏览器访问同一个Controller的某一个方法时,若在一个页签去访问,则controller中方法可以并行进行,符合预期。

若使用两个页签去访问同一个方法,则会出现该方法串行进行,通过测试发现其不是真正的串行,而是第二次访问时会等待好久才能访问到。

因此此问题定位到是浏览器的问题。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值