分布式锁(redis\ip\database)的一些实现方式及在实际中的应用

本文深入探讨分布式锁的四种实现方式:Redis锁、IP锁、数据库锁和Zookeeper锁,解析每种锁的工作原理与应用场景,为分布式系统设计提供指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分布式锁,在分布式架构中的锁的实现。接触到的使用情形主要分为两种情况:

一:该资源只允许一次访问,请注意,此种情况更像是一种独占,即并发情况下,只有一个线程能获取该资源,其他线程则放弃该资源。

二:该资源每次只允许一个线程访问,其他线程会不断尝试获取这个锁,直到所有线程都访问了这个资源。

 

1。redis实现分布式锁

在redis中设置一个锁名,和value值,再为这个锁名设置超时时间。

每次线程来访问先判断,这个锁名是否在redis中已经存在。如果存在则直接返回false表示该线程并未获取到锁。

设置超时时间,是为了防止死锁(某一线程获取锁后未释放该锁)。

代码:

/**
 * 加锁
 *
 * @param lockName 锁名
 * @param timeout 超时时间 秒
 * @return
 */
@Override
public boolean lock(String lockName, long timeout) {
    String  value = UUIDUtil.getUUID();
    String key = "key"+lockName;
    System.out.println(Thread.currentThread().getName()+"正在初步获取锁!");
   if(redisUtil.setIfAbsent(key,value)) {
       redisUtil.expire(key,timeout);
       return true;
   }
    return false;
}

 

/**
 * 释放锁
 *
 * @param lockName
 */
@Override
public void unLock(String lockName) {
redisUtil.del(lockName);
}

redisUtils中的方法:

/**
 * 当且仅当key不存在时,set一个key为val的字符串,返回true;若key存在,则什么都不做返回false
 *
 * @param key
 * @param value
 * @return
 */
public boolean setIfAbsent(String key,String value){
   return redisTemplate.opsForValue().setIfAbsent(key,value);
}
/**
 * 指定缓存失效时间
 * @param key 键
 * @param time 时间(秒)
 * @return
 */
public boolean expire(String key,long time){
    try {
        if(time>0){
            redisTemplate.expire(key, time, TimeUnit.SECONDS);
        }
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}
/**
 * 删除缓存
 * @param key 可以传一个值 或多个
 */
@SuppressWarnings("unchecked")
public void del(String ... key){
    if(key!=null&&key.length>0){
        if(key.length==1){
            redisTemplate.delete(key[0]);
        }else{
            redisTemplate.delete(CollectionUtils.arrayToList(key));
        }
    }
}

2.ip锁,通过获取服务器的ip和配置的可执行的ip是否一致,一致即获取了锁。及指定每次获取资源的服务器(这种其实就是把分布式变成了单机版)

public class IpLock implements ConcurrentLock {

 private  String hostAddress = IPUtil.getHostAddress();
    @Override
    public boolean lock(String lockName, long timeout) {
        String server_ip = PropertiesUtils.getApplicationProperties().getProperty("server_Ip");
        if(StringUtils.isNotBlank(hostAddress)&&StringUtils.isNotBlank(server_ip)){
            if(server_ip.equals(hostAddress)||server_ip.equals("localhost")){
                return true;
            }
        }
        return false;
    }

    @Override
    public void unLock(String lockName) {

    }
}

3.数据库锁,依赖数据库的行级锁,每次只能有一个线程获取到update的锁。如果更新成功表示获取到了锁。未更新成功即没有拿到锁。

public class dbLock implements ConcurrentLock {

    private static Logger logger = LoggerFactory.getLogger(dbLock.class);


    private DataSource dataSource;

    private ThreadLocal<Connection> connectionCatch = new ThreadLocal<>();

    @Override
    public boolean lock(String lockName, long timeout) {
        Connection connection = null;
        PreparedStatement ps = null;
        String sql = "update tb_dataBase_lock t set t.lock_version = t.lock_version + 1, t.update_date = sysdate where t.lock_name = ? ";
        try {
            connection = dataSource.getConnection();
            if(connection!=null&& !connection.isClosed()){
                connectionCatch.set(connection);
                connection.setAutoCommit(false);
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setString(1,lockName);
            int i = statement.executeUpdate();
            connection.close();
            return i==1;
            }
            return false;
        } catch (SQLException e) {
            connectionCatch.remove();
            logger.error(e.getMessage(),e);
            try {
                if(connection!=null&&!connection.isClosed()){
                    connection.close();
                }
                if(ps !=null && ps.isClosed()){
                    ps.close();
                }
            } catch (SQLException e1) {
                logger.error(e.getMessage(),e);
            }
        }
        return false;
    }

    @Override
    public void unLock(String lockName) {
        Connection connection = connectionCatch.get();
        try {
            if(connection == null|| connection.isClosed())return;
            connection.commit();
            connection.close();
        }catch (Exception e){
            logger.error(e.getMessage());
        }
        connectionCatch.remove();
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

 

4.zookeeperLock,利用zookeeper来实现分布式锁。

未完待续........

实际应用:通过AOP来统一写锁的逻辑。

自定义注解作为切入点(pointCut)。

定义锁的执行逻辑类作为通知(advice),具体可以实现methodInterceptor.

public class ConcurrentLockInterceptor implements MethodInterceptor {

    private Logger logger = LoggerFactory.getLogger(ConcurrentLockInterceptor.class);

    private Map<String,ConcurrentLock> locks;

    public void setLocks(Map<String, ConcurrentLock> locks) {
        this.locks = locks;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        LockRequired lockRequired = invocation.getMethod().getAnnotation(LockRequired.class);
        if(lockRequired == null){
            return invocation.proceed();
        }
        String lockName = lockRequired.lockName();
        if(StringUtils.isBlank(lockName)){
            lockName = invocation.getThis().getClass().getSimpleName()+"."+invocation.getMethod().getName();
        }
        ConcurrentLock lock = locks.get("redis");
        if(lockRequired.strategy().equals(LockRequired.LockStrategy.IP)){
            lock= locks.get("ip");
        }else if(lockRequired.strategy().equals(LockRequired.LockStrategy.DB)){
            lock = locks.get("db");
        }

        boolean locked =false;
        try {
            locked = lock.lock(lockName, lockRequired.timeout());
            if (locked) {
                logger.info("服务器【" + IPUtil.getHostAddress() + "】获取了锁【" + lockName + "】");
                invocation.proceed();
                lock.unLock(lockName);
            } else {
                logger.info("服务器【" + IPUtil.getHostAddress() + "】没获取到锁【" + lockName + "】跳过执行方法!");
            }
        }catch (Exception e){
            logger.error(e.getMessage());
            if(locked){
                lock.unLock(lockName);
                logger.debug("服务器["+IPUtil.getHostAddress()+"]成功释放锁["+lockName+"]");
            }

        }
        return null;
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值