Lock接口,和Synchronized区别,分布式锁

什么是锁:同步的本质是通过锁来实现的。为了实现多个线程在一个时刻同一个代码块只能有一个线程可执行,那么需要在某个地方做个标记,这个标记必须每个线程都能看到,当标记不存在时可以设置该标记,其余后续线程发现已经有标记了则等待拥有标记的线程结束同步代码块取消标记后再去尝试设置标记。这个标记可以理解为锁。

Lock接口
(1)Lock接口的实现类有:ReentrantLock,WriteLock,ReadLock,WriteLockView,ReadLockView。
(2)Lock接口中的方法:

  • tryLock():佛系获取锁,能获取就获取,获取不到就休眠。
  • tryLock(long,TimeUnit):有时间限制的佛系获取锁。

在单进程情况下,多个线程访问同一资源,可以使用synchronized和lock实现。在多进程情况下,也就是分布式情况,对同一资源的并发请求,需要使用分布式锁实现。下面分别说明一下。

1、单进程情况的锁,synchronized和lock的区别
(1)synchronized是java的关键字,在对象头设置标记,托管给jvm执行。lock是一个java实现的接口,使用voltile关键字修饰的一个变量,保证对所有线程的可见性和原子修改。
(2)因为第(1)中所说,synchronized对对象头的标记由jvm执行,获得锁和释放的方式都是在块结构中,自动释放锁。而Lock则需要开发人员手动去释放,并且必须在finally块中释放,否则会引起死锁问题的发生。

Lock的使用 
psvm 
private static int num = 0;
private static Lock lock = new ReentranLock();
public static void inCreate(){
	lock.lock();
	num++;
	lock.unlock();
}

(3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;通过Lock可以知道有没有成功获取锁tryLock()和尝试等待指定时长,而synchronized却无法办到。Lock可以提高多个线程进行读操作的效率。
(4)synchronized锁的范围是整个方法或synchronized块部分;而Lock因为是方法调用,可以跨方法,灵活性更大。
(5)Lock是乐观锁,是CAS机制,每次不加锁,遇到重入失败就重试,直到成功为止;Synchronized是悲观锁,线程获取的是独占锁,其他线程只能被阻塞,等待线程释放锁。(悲观锁、乐观锁的区别及使用场景
(6)Lock的使用和Synchronized的效果是一样的。
(7)JDK1.5之前,Synchronized性能不好,现在的版本JDK1.6,好多了,和Lock的性能差不多了。

ReentrantLock的使用

2、分布式锁
主要实现方式:基于数据库、redis、zk实现。
Java分布式锁看这篇就够了

基于redis实现的分布式锁:

public class RedisLock {
    @Autowired
	private RedisService redisService;
    public boolean tryLock(String lockKey, String value, long expireTime) {
        if (!StringUtil.isBlank(lockKey) && !StringUtil.isBlank(value) && expireTime > 0L) {
            try {
                boolean successFlag = this.redisService.setNX(lockKey, value);
                if (successFlag) {
                    boolean expireFlag = this.redisService.expire(lockKey, expireTime, TimeUnit.SECONDS);
                    return true;
                } else {
                    return false;
                }
            } catch (RuntimeException var7) {
                LOG.error("RedisLock-->tryLock error", var7);
                return false;
            }
        } else {
            LOG.error("RedisLock-->tryLock invalid parameter");
            return false;
        }
    }

    public void unLock(String lockKey) {
        if (StringUtil.isBlank(lockKey)) {
            LOG.error("RedisLock-->unLock invalid parameter");
        } else {
            try {
                this.redisService.del(lockKey);
                if (!this.redisService.exists(lockKey)) {
                    LOG.debug("RedisLock-->unLock release lock success lockKey:{}", lockKey);
                } else {
                    LOG.error("RedisLock-->unLock release lock error lockKey:{}", lockKey);
                }
            } catch (RuntimeException var3) {
                LOG.error("RedisLock-->unLock execute error ", var3);
            }
        }
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章