java中的锁,最基本的是Lock接口。

Lock接口中的方法,主要是:

  • lock(): 获取锁,lock()方法会对Lock实例对象进行加锁,因此所有对该对象调用lock()方法的线程都会被阻塞,直到该Lock对象的unlock()方法被调用。
  • unlock(): 释放锁, Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁。

常用的锁有 可重入锁ReentrantLock、读写锁ReadWriteLock

代码如下:

Lock lock = new ReentrantLock(); // Lock 接口的实现类
void show() {
try {
lock.lock(); //获取锁
// 执行逻辑代码...
}catch(){ } finally {
lock.unlock(); // 释放锁
}
}

 可重入性

如果一个线程已经拥有了一个管程对象上的锁,那么它就有权访问被这个管程对象同步的所有代码块。这就是可重入。

Java中的synchronized同步块是可重入的。这意味着如果一个java线程进入了代码中的synchronized同步块,并因此获得了该同步块使用的同步对象对应的管程上的锁,那么这个线程可以进入由同一个管程对象的另一个synchronized代码块。

当然,并不是所有的锁都具有可重入性。

公平性

如果多个线程不断竞争访问相同的synchronized同步块,就存在一种风险,其中一个或多个线程永远也得不到访问权 —— 也就是说访问权总是分配给了其它线程。这种情况被称作线程饥饿。为了避免这种问题,锁需要实现公平性。

公平锁是指多个线程获取锁被阻塞的情况下,锁变为可用时,最先申请锁的线程获得锁。

可重入锁ReentrantLock

ReentrantLock的功能类似于synchronized。而且具备更多的功能。比如设置Condition条件。

ReentrantLock lock = new ReentrantLock(); //参数默认false,不公平锁

ReentrantLock lock = new ReentrantLock(true); //公平锁

读写锁ReadWriteLock

在没有写操作的时候,两个线程同时读一个资源没有任何问题,允许多个线程同时读取共享资源。

但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写。

简单来说,多个线程同时操作同一资源时,“读读共存,写写不共存,读写不共存”。

读写锁的锁定规则如下:
获得读锁后,其它线程可获得读锁而不能获取写锁
获得写锁后,其它线程既不能获得读锁也不能获得写锁

05-11 17:21