redisson提供了基于redis的分布式锁实现方式,本文就尝试了下锁的使用方式。Redisson同时还为分布式锁提供了异步执行的相关方法,第二节执行介绍。

一、可重入锁验证 

同一个jvm里面同一线程的锁是可重入锁,redisson也提供了这种方式,像使用本地锁一样使用分布式锁。

public static void main(String[] args){
        ApplicationContext act = SpringApplication.run(NesttyMain.class, args);
//        SpringUtil.setApplicationContext(act);
        RedissonHelper redissonHelper = (RedissonHelper) act.getBean("redissonHelper");
        //获取一个非公平锁,非公平是指不保证按照线程获取顺序返回锁
        RLock lockNonFair = redissonHelper.lockNonFair("test");
        //模拟两个不同jvm的锁
        RLock lockNonFair2 = redissonHelper.lockNonFair("test");
        //线程1,假设先获取到锁了
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //执行加锁
                lockNonFair.lock();
                try {
                    System.out.println("thread1, mock execute method start!"+new Date());
                    getLockAgain();
                    Thread.sleep(10000);
                    System.out.println("thread1, mock execute method end!"+new Date());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //释放锁,这时thread1执行锁释放
                    lockNonFair.unlock();
                }

            }

            //验证锁可重入
            public void getLockAgain(){
                lockNonFair.lock();
                try {
                    System.out.println("thread1-method, mock execute method start!"+new Date());
                    Thread.sleep(10000);
                    System.out.println("thread1-method, mock execute method end!"+new Date());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //执行一次unlock,并没有立即让thread2获取到锁
                    lockNonFair.unlock();
                }
            }
        });
        thread1.start();

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                //由于thread1的业务总共需要执行20s,这根线程就拿不到锁一直阻塞在这
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                lockNonFair2.lock();
                try {
                    System.out.println("thread2, mock execute method start!"+new Date());
                    Thread.sleep(5000);
                    System.out.println("thread2, mock execute method end!"+new Date());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //执行完成释放锁
                    lockNonFair2.unlock();
                }
            }
        });
        thread2.start();
    }

最后,打印输出

thread1, mock execute method start!Sat Dec 15 16:20:35 CST 2018

--thread1加锁执行
thread1-method, mock execute method start!Sat Dec 15 16:20:35 CST 2018

--thread1重入锁执行
thread1-method, mock execute method end!Sat Dec 15 16:20:45 CST 2018

--thread1重入锁执行完成
thread1, mock execute method end!Sat Dec 15 16:20:55 CST 2018

--thread1加锁执行完成锁
thread2, mock execute method start!Sat Dec 15 16:20:55 CST 2018

--thread2获取到锁
thread2, mock execute method end!Sat Dec 15 16:21:00 CST 2018

--thread2获取执行完成释放锁

二、可重入锁的异步形式

一个加正常锁,一个加锁的分布式形式如下:

进程1中加非异步锁
Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                //由于thread1的业务总共需要执行20s,这根线程就拿不到锁一直阻塞在这
                lockNonFair.lock();
                try {
                    System.out.println("thread2,sync start!"+new Date()+", lock holdCount="+lockNonFair.getHoldCount()+", thread id"+Thread.currentThread().getId());
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //执行完成释放锁
                    lockNonFair.unlock();
                    System.out.println("thread2,sync end!"+new Date()+", lock holdCount="+lockNonFair.getHoldCount()+", thread id"+Thread.currentThread().getId());
                }
            }
        });
        thread2.start();
//thread2,sync start!Sat Dec 15 17:21:38 CST 2018, lock holdCount=1, thread id48
//thread2,sync end!Sat Dec 15 17:21:48 CST 2018, lock holdCount=0, thread id48
进程2中加异步锁
Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                //起一根线程进行异步加锁,发现
                lockNonFair.lockAsync();
                try {
                    System.out.println("thread2, start!"+new Date()+", lock holdCount="+lockNonFair.getHoldCount()+", thread id"+Thread.currentThread().getId());
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //执行完成释放锁
                    lockNonFair.unlock();
                    System.out.println("thread2, end!"+new Date()+", lock holdCount="+lockNonFair.getHoldCount()+", thread id"+Thread.currentThread().getId());
                }
            }
        });
        thread2.start();
//thread2,sync start!Sat Dec 15 17:21:48 CST 2018, lock holdCount=1, thread id48
//thread2,sync end!Sat Dec 15 17:21:58 CST 2018, lock holdCount=0, thread id48
发现是进程1执行完再执行进程2

如果全部都改成lockAsync()之后执行输出如下:

thread2,start!Sat Dec 15 17:30:25 CST 2018, lock holdCount=0, thread id48
thread2,end!Sat Dec 15 17:30:35 CST 2018, lock holdCount=0, thread id48

thread2,start!Sat Dec 15 17:30:23 CST 2018, lock holdCount=0, thread id48
thread2,end!Sat Dec 15 17:30:33 CST 2018, lock holdCount=0, thread id48

虽然线程名字不一样,但是加了锁异步实现方式发现执行顺序不是按照等待上一次锁的执行。

12-15 20:43