Common examples of distributed lock and redisson

Demand Background:

在分布式多机部署的情况下,我们要求某一个方法,只能同一个时间只能被一台机器的一个线程执行。

In stand-alone, there are synchronized, read-write locks, and other ways to solve the synchronization problem. However, these can only act on the same machine, the method can only guarantee one machine will not perform at the same time. Multiple machines can still be performed simultaneously.

At this time, we need the help of the media redisson, based on a distributed lock redis. .

Premise much to say, first installed redis, Redis main use from + Sentinel mode. Here multiple machines installed redis Sentinel can also be installed stand-alone multi-port

Add dependence:

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.8.2</version>
</dependency>

1.1 First create RedissonManager get redisson

package com.test.redisson.manager;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
/**
 * @version 1.0.0
 * @description
 * @date 2018/05/04 16:54
 **/
public class RedissonManager {

    private static RedissonClient redissonClient;
    private static Config config = new Config();
    /**
     * 初始化Redisson,使用哨兵模式
     */
    public static void init(){
        try {
            config.useSentinelServers()
                    .setMasterName("cache")
                    .addSentinelAddress("10.0.0.1:26379","10.0.0.2:26379", "10.0.0.3:26379")
                    //同任何节点建立连接时的等待超时。时间单位是毫秒。默认:10000
                    .setConnectTimeout(30000)
                    //当与某个节点的连接断开时,等待与其重新建立连接的时间间隔。时间单位是毫秒。默认:3000
                    .setReconnectionTimeout(10000)
                    //等待节点回复命令的时间。该时间从命令发送成功时开始计时。默认:3000
                    .setTimeout(10000)
                    //如果尝试达到 retryAttempts(命令失败重试次数) 仍然不能将命令发送至某个指定的节点时,将抛出错误。如果尝试在此限制之内发送成功,则开始启用 timeout(命令等待超时) 计时。默认值:3
                    .setRetryAttempts(5)
                    //在一条命令发送失败以后,等待重试发送的时间间隔。时间单位是毫秒。     默认值:1500
                    .setRetryInterval(3000)
            ;
            redissonClient = Redisson.create(config);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /**
     * 获取Redisson的实例对象
     * @return
     */
    public static Redisson getRedisson(){
        init();
        return (Redisson) redissonClient;
    }
    /**
     * 测试Redisson是否正常
     */
    public static void main(String[] args) {
        Redisson redisson = RedissonManager.getRedisson();
        System.out.println("redisson = " + redisson);
    }
}

Lock operation LockUtil 1.2

package com.test.redisson.lockutil;
import com.test.redisson.manager.RedissonManager;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import java.util.concurrent.TimeUnit;
/**
 * Redisson分布式锁 工具类
 */
public class LockUtil {
    private static Redisson redisson = RedissonManager.getRedisson();
    /**
     * 根据name对进行上锁操作,redisson Lock 一直等待获取锁
     * @param lockname
     */
    public static void lock(String lockname) throws InterruptedException {
        String key = lockname;
        RLock lock = redisson.getLock(key);
        //lock提供带timeout参数,timeout结束强制解锁,防止死锁 
        lock.lock(60L, TimeUnit.SECONDS);
    }

    /**
     * 根据name对进行上锁操作,redisson tryLock  根据第一个参数,一定时间内为获取到锁,则不再等待直接返回boolean。交给上层处理
     * @param lockname
     */
    public static boolean tryLock(String lockname) throws InterruptedException {
        String key = lockname;
        RLock lock = redisson.getLock(key);
        //tryLock,第一个参数是等待时间,5秒内获取不到锁,则直接返回。 第二个参数 60是60秒后强制释放
        return lock.tryLock(5L,60L, TimeUnit.SECONDS);
    }
    /**
     * 根据name对进行解锁操作
     * @param lockname
     */
    public static void unlock(String lockname){
        String key = lockname;
        RLock lock = redisson.getLock(key);
        lock.unlock();
    }
}

1.3 RedissonTestLock (tested packaged Method)

package com.test.redisson.test;
import com.test.redisson.lockutil.LockUtil;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * @version 1.0.0
 * @description
 * @date 2018/05/04 17:02
 **/
public class RedissonTestLock {
    public static void main(String[] args) {
        //模拟2个线程
        for (int i = 1; i <= 2; i++) {
            //可以开2个IDE,分别测试以下三个方法
            //打开2个IDE同时执行时,这里可以分别取不同名,区分
            new Thread("IDE-ONE-"+i) {
                @Override
                public void run() {
                    /**
                     * 测试testLock结果,每个IDE中线程,依次排队等待获取锁。然后执行任务
                     */
                    testLock("redissonlocktest_testkey");

                    /**
                     * 测试testTryLock结果,每个IDE中线程,在TryLock的等待时间范围内,若获取到锁,返回true,则执行任务;若获取不到,则返回false,直接返回return;
                     */
//                    testTryLock("redissonlocktest_testkey");

                    /**
                     * 测试testSyncro结果,IDE之间的线程互不影响,同一个IDE中的线程排队值执行,不同IDE之间的互补影响,可同时执行
                     */
//                    testSyncro("redissonlocktest_testkey");
                }
            }.start();
        }
    }

    //测试lock,拿不到lock就不罢休,不然线程就一直block。
    public static void testLock(String preKey) {
        try {
            System.out.println(getDate()+Thread.currentThread().getName() + "准备开始任务。。。。");
            LockUtil.lock(preKey);
            System.out.println(getDate()+Thread.currentThread().getName() + "模拟正在执行任务。。。。");
            Thread.sleep(5000);//等待5秒,后面的所有线程都“依次”等待5秒,等待获取锁,执行任务

        } catch (Exception e) {
            System.out.println(getDate()+"线程锁 :" + Thread.currentThread().getId() + " exception :" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            e.printStackTrace();
        } finally {
            LockUtil.unlock(preKey);
            System.out.println(getDate()+Thread.currentThread().getName() + "释放。。。。");
        }
    }

    //带时间限制的tryLock(),拿不到lock,就等一段时间,超时返回false。
    public static void testTryLock(String preKey) {

        try {
            System.out.println(getDate()+Thread.currentThread().getName() + "准备开始任务。。。。");
            boolean falg = LockUtil.tryLock(preKey);
            //这里若获取不到锁,就直接返回了
            if(!falg){
                System.out.println(getDate()+Thread.currentThread().getName() + "--没有获取到锁直接返回--" + falg);
                return;
            }
            System.out.println(getDate()+Thread.currentThread().getName() + "--获取锁--" + falg);
            System.out.println(getDate()+Thread.currentThread().getName() + "模拟正在执行任务。。。。");

           //由于在LockUtil.tryLock设置的等待时间是5s,所以这里如果休眠的小于5秒,这第二个线程能获取到锁,
            // 如果设置的大于5秒,则剩下的线程都不能获取锁。可以分别试试2s,和8s的情况
            Thread.sleep(8000);//等待6秒

        } catch (Exception e) {
            System.out.println(getDate()+"线程锁 :" + Thread.currentThread().getId() + " exception :" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            e.printStackTrace();
        } finally {
            try {
                LockUtil.unlock(preKey);
                System.out.println(getDate()+Thread.currentThread().getName() + "释放。。。。");
            }catch (Exception e){
                e.printStackTrace();
            }

        }
    }

    //synchronized 这种锁只能锁住同一台机器的线程,若部署多台机器,则不能锁住
    public static void testSyncro(String preKey) {
        synchronized (preKey.intern()){//为什么要intern前篇文章有解释
            try {
                System.out.println(getDate()+Thread.currentThread().getName() + "准备开始任务。。。。");
                System.out.println(getDate()+Thread.currentThread().getName() + "--获取锁--" );
                System.out.println(getDate()+Thread.currentThread().getName() + "模拟正在执行任务。。。。");
                Thread.sleep(6000);//执行2秒
            } catch (Exception e) {
                System.out.println(getDate()+"线程锁 :" + Thread.currentThread().getId() + " exception :" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                e.printStackTrace();
            } finally {
                try {
                    System.out.println(getDate()+Thread.currentThread().getName() + "释放。。。。");
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
    public static String getDate(){
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"   ";
    }
}

Common examples of distributed lock redisson

Simulated multi-threaded competing for the same resources, the use of distributed locks for redisson

 public void testMultiThread() throws Exception{
        final Config config = new Config();
        config.useSingleServer().setAddress("192.168.3.199:6379").setConnectionPoolSize(5);
        //开启多线程去竞争同一个资源锁
        for (int i = 0; i < 12; i++) {
            new Thread(new Runnable() {
                @SuppressWarnings("static-access")
                @Override
                public void run() {
                    RedissonClient redisson = Redisson.create(config);
                    RLock lock = redisson.getLock("anyLock"); //设置锁对象
                    boolean res = false;
                    try {
                        // 尝试加锁,最多等待10秒,上锁以后3秒自动解锁
                        res = lock.tryLock(10, 3, TimeUnit.SECONDS);
                      if(res){//获取锁成功
                        try { 
                            //业务操作 
                            Thread.currentThread().sleep(new Random().nextInt(2)*1000); 
                        }finally{ 
                            lock.unlock(); 
                            } 
                        } 
                      System.err.println("ThreadID:"+Thread.currentThread().getId()+",res="+res); } 
                    catch (InterruptedException e) { 
                        log("尝试获取锁异常:"+e); 
                    } 
                }}).start(); 
            } 
        }
Published 14 original articles · won praise 2 · Views 807

Guess you like

Origin blog.csdn.net/breakaway_01/article/details/102724577