Lock 与 sychronize 简析

本文详细比较了Lock与synchronized的区别,指出Lock提供了更强大的锁操作和条件对象,可避免死锁并支持中断。ReentrantLock作为Lock的实现,支持可重入性和读写分离,提高读操作效率。同时,Lock的Condition接口允许选择性通知,避免了synchronized的随机唤醒问题。总结了Lock在并发控制中的优势和适用场景。
摘要由CSDN通过智能技术生成

1.1 与 synchronized 对比

Lock 锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作。它们允许更灵活的结构,可能具有非常不同的属性,并且可能支持多个关联的条件对象。Lock 提供了比 synchronized 更多的功能。

区别:

  • Lock 非 Java 语言内置的是一个类, synchronized 是 Java 语言的关键字,incident是内置特性。
  • synchronized 不需要手动释放锁,当其修饰的部分执行完后,线程自动释放锁。Lock 必须手动释放锁,若不主动释放可能出现死锁现象。

1.2 lock 介绍

public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition()
}

1.2.1 lock和unlock与一般格式

lock() 和 unlock() 分别为上锁和解锁

一般使用格式:

Lock lock = ...;
lock.lock();
try{
    //处理的任务
}catch(Exception ex){
    
}finally{
    lock.unlock();
}

1.2.2 newCondition

相对于 synchronized 与 wait()/notify() 这两个方法一起使用可以实现等待/通知模式,Lock 锁的 newCondition() 方法返回 Condition 对象,Condition 类也可以实现等待/通知模式。

用 notify() 通知时, JVM 会随机唤醒某个等待的线程,使用 Condition 类可以进行选择性的通知。

Condition常用的两个方法:

  • await():使当前线程等待,并释放锁,其他线程调用 signal() 时,线程重新获得锁并继续执行。
  • signal():唤醒一个等待的线程。

注意:调用 Condition 的两个方法前,也需要线程持有相关的 Lock 锁,调用 await() 后线程会释放这个锁,在 signal() 调用后会从当前 Condition 对象的等待队列中唤醒一个线程,唤醒的线程尝试获得锁,一旦获得锁成功就继续执行。

1.3 ReentrantLock 类

可重入锁,是唯一实现 Lock 接口的类,并且 ReentrantLock 提供了更多的方法。

可重入锁:若线程A获取某一方法的锁后,线程B也要获取该方法的锁,假如该锁为不可重入锁,则B会进入一直等待的状态,出现自我死锁。(因此 synchronized 也是可重入锁)

ReentrantLock 类具有完全互斥排他的效果,同一时间只有一个线程在执行 ReentrantLock.lock() 方法后面的任务,这样做虽然保证了同时写实例变量的线程安全性,但效率低下。(这也是和 ReentrantReadWriteLock 类相比最主要的缺点)

因此jdk亦提供了 ReentrantReadWriteLock 类,使用它时可以在进行读操作时不需要同步执行,提升运行速度,加快运行效率。

1.4 ReadWriteLock 接口

public interface ReadWriteLock {
/**
* Returns the lock used for reading.
*/
Lock readLock();
/**
* Returns the lock used for writing.
*/
Lock writeLock();
}

一个用来获取读锁(共享锁),一个用来获取写锁(排他锁)。

即,将文件的读写操作分开,分成两个锁来分配给线程,从而使得多个线程可以同时进行读操作。

读操作:读取实际变量的值。写操作:向实例变量写入值。

**ReentrantReadWriteLock **实现了 ReadWriteLock 接口。其中有很多方法,但最重要的是 readLock() 和 writeLock() 两种方法。

读锁之间不互斥,写锁和读锁或写锁都有互斥效果。

1.5 小结

  1. Lock 是 synchronized 的进阶,完全可以取代后者,并且有更丰富的功能。
  2. Lock 是接口, synchronized 是关键字,后者是内置的语言实现。
  3. synchronized 在发生以长时,会自动释放线程占有的锁,因此不会导致死锁现象的发生;而 Lock 发生异常时,如果没有主动通过 unlock() 去释放锁,则很可能造成死锁现象,因此使用 lock 时需要在 finally 块中释放锁。
  4. Lock 可以让等待锁的线程响应中断,而 synchronized 不行,使用它的线程会一直等待下去,不能够响应中断。
  5. 通过 lock 可以知道是否成果获取锁,而 synchronized 不可以。
  6. Lock 实现读写操作分离,可以提高多个线程的读操作效率。
  7. 读读异步,读写互斥,写读互斥,写写互斥。
  8. 当资源竞争十分激烈时(大量线程同时竞争),lock 的性能远远优于 synchronized。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咀才

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值