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:
在没有写操作的时候,两个线程同时读一个资源没有任何问题,允许多个线程同时读取共享资源。
但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写。
简单来说,多个线程同时操作同一资源时,“读读共存,写写不共存,读写不共存”。
读写锁的锁定规则如下:
获得读锁后,其它线程可获得读锁而不能获取写锁
获得写锁后,其它线程既不能获得读锁也不能获得写锁