一、Lock 接口
1. 主要特性
特性 | 描述 |
---|---|
尝试非阻塞获取锁 | 当前线程尝试获取锁,如果这一刻锁没有被其他线程获取到,则成功获取并持有锁; |
能被中断地获取锁 | 获取到锁的线程能够响应中断时,中断异常将会被抛出,同时锁会被释放; |
超时获取锁 | 在指定的截止时间之前获取锁,如果截至时间到了任就无法获取锁,则返回; |
2. API
方法名称 | 描述 |
---|---|
void lock() | 获取锁,调用该方法当前线程将会获取锁,当锁获得后,从该方法返回 |
void lockInterruotibly() throws InterruptedException | 可中断的获取锁,锁的获取中可以中断当前线程 |
boolean tryLock() | 尝试非阻塞的获取锁,调用该方法后立刻返回,如果能够获取则返回true 否则返回 false |
boolean tryLock(long time,TimeUnit unit) throws InterruptedException | 超时获取锁,遇到一下三种情况会返回:1. 当前线程在尝试时间内获得了锁 2. 当前线程在超时时间内获得了锁 3.超市时间结束,返回 false |
void unlock() | 释放锁 |
Codition newCondition() | 获取等待通知组件,该组件和当前锁绑定,当前线程只有获得了锁,才能调用该组件的 wait() 方法,调用后将释放锁 |
二、队列同步器
队列同步器 :是用来构建锁或者其他同步组件的基础框架,通过继承的方式,子类通过继承同步器并实现它的抽象方法来管理同步状态;
使用如下 3 个方法来访问和修改同步状态:
- getState () :获取当前同步状态;
- setState ( int new State ):设置当前同步状态;
- compareAndSetState ( int expect ,int upate):使用 CAS 来保证状态设置的原子性;
同步器可重写的方法 :
方法名称 | 描述 |
---|---|
protected boolean tryAcquire ( int arg) | 独占式获取同步状态,先查询当前状态并判断是否符合预期,然后在进行 CAS 设置同步状态 |
protected boolean tryRelease ( int arg) | 独占式释放同步状态,等待获取同步状态的线程将有机会获取同步状态 |
potected int tryAcquireShared( int arg ) | 共享式获取同步状态,返回大于等于 0 的值,表示获取成功,繁殖获取失败 |
protected boolean tryReleaseShared( int arg ) | 共享式释放同步状态 |
protected boolean isHeldExclusively() | 当前同步器是否在独占模式下被线程占用,一般该方法表示是否被当前线程独占 |
同步器提供的模板方法:
方法名称 | 描述 |
---|---|
void acquire (int arg) | 独占式获取同步状态,如果当前线程获取同步状态成功,则由该方法返回,否则,将会进入同步队列等待,该方法将会调用重写的 tryAcquire ( int arg ) 方法 |
void acquireInterrupibly ( int arg) | 与 acquire ( int arg )相同,但是该方法响应中断,当前线程未获取到同步状态而进入同步队列中,如果当前线程被中断,则该方法会抛出 InteruptedException 并返回 |
boolean tryAcqireNanos(int arg,long nanos) | 在acquireInterruptibly(int arg) 基础上增加了超时限制,如果当前线程在超时时间内没有获取到同步状态,那么将会返回 false ,如果获取到了返回 true |
void acquireShared(int arg) | 共享式的获取到同步状态,如果当前线程未获取到同步状态,将会进入同步队列等待,与独占式获取的主要区别是在同一时刻可以有多个线程获取到同步状态 |
void acquireSharedInterruptibly (int arg) | 与acquireShared(int arg) 相同,该方法响应中断 |
boolean tryAcquireSharedNanos ( int arg,long nanos) | 在acquireSharedInterruptibly (int arg)基础上增加了超时限制 |
boolean release(int arg) | 独占式的释放同步状态,该方法会在释放同步状态之后,将同步队列中第一个节点包含的线程唤醒 |
boolean raleaseShared(int arg) | 共享式的释放同步状态 |
Collection< Thread > getQueuedThreads() | 获取等待在同步队列上的线程集合 |
三、重入锁
重入锁 :支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁,还支持获取锁时的公平和非公平性选择
1. 实现重进入
重进入 :是指任意线程在获取到锁之后能够再次获取到该锁而不会被锁所阻塞,该特性实现需要解决两个问题:
- 线程再次获取 :锁要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次成功获取;
- 锁的最终释放 :锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数器自减,为 0 时表示锁已经释放;
2. 公平锁和非公平锁
公平锁 :所得获取顺序应该符合请求的绝对顺序(FIFO );
非公平锁 :CAS 设置同步状态成功,当前线程获得锁;
公平锁保证了锁按照 FIFO 原则,而代价是进行大量的线程切换;
非公平锁虽然可能造成线程 “ 饥饿 ” ,但是极少的线程切换,保证了其更大的吞吐量;
四、读写锁
读写锁 :在同一时刻允许多个线程访问,不同于其他排他锁的同一时刻只能有一个线程来访问,在写线程访问时,所有的读线程和其他写线程都被阻塞,当线程锁被获取到时,后续(非当前写操作线程)的读写都会被阻塞,写锁释放之后,所有的操作继续执行;
Java 并发包提供了ReentrantReadWriteLock来实现读写锁,其特性如下:
特性 | 说明 |
---|---|
公平性选择 | 支持非公平锁(默认)和公平的锁获取方式,吞吐量还是非公平优于公平 |
重进入 | 读线程在获取读锁之后,能够再次获取读锁,而写线程在获取写锁之后能够再次获取写锁,同时也可以获取读锁 |
锁降级 | 遵循获取写锁,获取读锁再释放写锁的次序,写锁能够降级为读锁 |
1. 读写锁的接口
ReentrantReadWriteLock展示内部工作状态的方法
方法名称 | 描述 |
---|---|
int getReadLockCount() | 返回当前读锁被获取的次数,该次数不等于获取读锁的线程数 |
int getReadHoldCount() | 返回当前线程读锁被获取的次数 |
boolean isWriteLocked() | 判断写锁是否被获取 |
int getWriteHoldCount() | 返回当前写锁被获取的次数 |
2. 写锁的获取与释放
写锁是一个支持重进入的排他锁 ,线程已经获取锁时。增加锁状态,读锁已经被获取或者线程不是获取锁的线程,则进入等待状态,当写状态为 0 时表示锁已经释放;
3. 读锁的获取与释放
读锁是一个支持重进入的共享锁,它能够被多个线程同时获取,在没有其他写线程访问时,读锁总会被成功的获取,如果当前线程在获取都所示,写锁已经被其他线程获取,则进入等待状态;
4. 锁降级
锁降级是指把持住当前拥有的写锁,再获取到读锁,随后释放先前拥有的写锁的过程