通过redis实现对于分布式的环境下的并发管理

使用定时器时,部署到多个节点,共同访问一个库,导致任务重复执行,然后想到了使用redis来实现锁原理.

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.util.concurrent.TimeUnit;

/**
 * 通过redis实现对于分布式的环境下的并发管理(通过redis锁实现并发处理)
 */
public class RedisDistributionLock implements DistributionLock {
    private long lockTimeout;
    private final RedisTemplate redisTemplate;
    private final String lockKey;
    private final RedisSerializer keyRedisSerializer;
    private final RedisSerializer valueRedisSerializer;

    public RedisDistributionLock(RedisTemplate redisTemplate, String key, long timeout) {
        this.redisTemplate = redisTemplate;
        this.lockTimeout = timeout;
        this.lockKey = key;
        this.keyRedisSerializer = redisTemplate.getKeySerializer();
        this.valueRedisSerializer = redisTemplate.getValueSerializer();

    }

    //尝试获取一次锁
    public synchronized boolean tryLock() {
        long currentTime = System.currentTimeMillis();
        Long lock_timeout = currentTime + lockTimeout;
        if (redisTemplate.execute(new LockRedisCallBack(this.lockKey, lock_timeout))) {
            redisTemplate.expire(lockKey, lockTimeout, TimeUnit.MILLISECONDS);
            return true;
        } else {
            RedisLockObject redisLockObject = null;
            try {
                Object object = redisTemplate.opsForValue().get(lockKey);
                if (object != null) {
                    redisLockObject = (RedisLockObject) redisTemplate.opsForValue().get(lockKey);
                }

            } catch (Exception err) {
                redisTemplate.delete(lockKey);
                err.printStackTrace();
            }
            if (redisLockObject != null && (redisLockObject.getTimeout() < currentTime)) {
                long oldTimeout = redisLockObject.getTimeout();
                redisLockObject.setTimeout(lockTimeout);
                RedisLockObject oldRedisLockObject = (RedisLockObject) redisTemplate.opsForValue().getAndSet(lockKey, redisLockObject);
                if (oldRedisLockObject != null && oldRedisLockObject.getTimeout() == oldTimeout) {
                    redisTemplate.expire(lockKey, lockTimeout, TimeUnit.MILLISECONDS);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 加锁 取到锁加锁,取不到锁就返回
     *
     * @return
     */
    @Override
    public synchronized long lock() {
        while (true) {
            if (tryLock()) {
                return System.currentTimeMillis() + lockTimeout;
            }
            try {
                Thread.sleep(10);
            } catch (Exception err) {
                err.printStackTrace();
            }
        }
    }

    /**
     * 解锁
     */
    @Override
    public synchronized void unlock() {
        RedisLockObject redisLockObject = (RedisLockObject) redisTemplate.opsForValue().get(lockKey);
        if (redisLockObject != null) {
            redisTemplate.delete(lockKey);
        }
    }


    @SuppressWarnings("rawtypes")
    private class LockRedisCallBack implements RedisCallback {
        private long timeOut;

        public LockRedisCallBack(String key, long timeOut) {
            this.timeOut = timeOut;
        }


        @SuppressWarnings("unchecked")
        @Override
        public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
            RedisLockObject redisLockObject = new RedisLockObject();
            redisLockObject.setTimeout(timeOut);
            byte[] value = valueRedisSerializer.serialize(redisLockObject);
            byte[] key = valueRedisSerializer.serialize(lockKey);
            return connection.setNX(key, value);
        }
    }
}
public interface DistributionLock {

    public long lock();

    public void unlock();

}

你可能感兴趣的:(通过redis实现对于分布式的环境下的并发管理)