您当前的位置:首页 > 计算机 > 编程开发 > Java

Java 线程锁

时间:12-14来源:作者:点击数:
城东书院 www.cdsy.xyz

ReentrantLock

ReentrantLock 是在编程对象层次的可重入锁,synchronized 是关键字,是语言特性上的锁。

ReentrantLock 相对于 synchronized 而言更灵活,ReentrantLock 能够通过 Condition 指定线程唤醒,是否响应中断,尝试获取锁,获取当前锁状态(等待线程数等),是否是公平锁。

关键方法 说明
boolean trylock() 尝试获取锁,不阻塞,成功返回 true,失败返回 false。
boolean trylock(long timeout,TimeUnit unit) 等待指定时间后再尝试获取锁,成功返回true,失败返回false。
void lock() 获取锁,该方法会阻塞,直至获取到锁。
void lockInterruptibly() throws InterruptedException 获取锁,该方法会阻塞,直至获取到锁。若调用该方法是,当前线程已经 interrupt 则抛出异常。
Boolean isLocked() 当前锁是否已经有线程占用,是则返回true,否则返回false。
void unlock() 释放锁,该方法建议放在finally中使用。
int getHoldCount() ReentrantLock支持重入,此方法返回同一个线程当中,lock的总次数-unlock总次数
Condition newCondition() 返回一个Condition变量,用于指定线程的等待-唤醒

Condition

关键方法 说明
void awaitUninterruptibly() 使当前线程等待,调用这个方法时,即使当前线程interrupt,也不会报异常。
void await() 使当前线程等待,调用这个方法时,如果当前线程interrupt则报异常。
void signal() 唤醒等待的其中一个线程。
void signalAll() 唤醒所有等待线程。
long awaitNanos(long nanosTimeout) throws
InterruptedException 等待指定时间,调用这个方法时,若当前线程interrupt,则报异常。

Reentrant 与 Condition

  1. 使用 Condition 的 await 功能方法时,必须保证已经获得锁。
  2. await 方法执行后会释放锁
  3. aignal、signalAll 执行后不会释放锁。
static ReentrantLock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
static Runnable runnable = new Runnable() {
 public void run() {
 Thread.currentThread().interrupt();
 System.out.println(Thread.currentThread().getName()+ "start");
 try {
 lock.lock();
 condition.awaitUninterruptibly();} catch (Exception e) {}
 finally {
 lock.unlock();
 }
 System.out.println(Thread.currentThread().getName()+ "end");
 }
};
public static void main(String[] arg) throws Exception
{
 new Thread(runnable).start();
 new Thread(runnable).start();
 Thread.sleep(5000);
 {
 lock.lock();
 condition.signalAll();
 System.out.println("unlock");
 lock.unlock();
 }

ReentrantReadWriteLock

ReentrantReadWriteLock有两把锁,分别是读锁和写锁,其中 读操作与读操作允许并发,读写 写读 写写 必须是互斥执行。

关键方法 说明
ReentrantReadWriteLock.WriteLock writeLock() 获取写锁
ReentrantReadWriteLock.ReadLock readLock() 获取读锁
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
// Condition readCon = lock.readLock().newCondition(); // 读锁不能创建condition
Condition writeCon = lock.writeLock().newCondition();

当有大量读线程少量写线程的时候,写线程会迟迟获取不到锁而处于等待状态。

StampedLock

StampedLock 是 ReentrantReadWriteLock 的改进,stampedLock 提供读锁、写锁、乐观读锁。读锁和写锁和 ReentrantLock 功能一样,读读并发,读写、写读、写写互斥。获取锁后会返回一个long值,释放锁需要将这个值传入。

关键方法 说明
long readLock() 获取写锁
long writeLock() 获取读锁
long tryOptimisticRead() 获取乐观读锁
void unlock(long stamp) 释放读锁或写锁,全能型
void unlockWrite(long stamp) 只能释放写锁,若释放读锁则抛异常
void unlockRead(long stamp) 只能释放读锁,若释放写多则抛异常

基本使用方法:

StampedLock lock = new StampedLock();
long locklong = lock.readLock();
……
lock.unlockRead(locklong);
long locklong = lock.writeLock();
……
lock.unlockWrite(locklong);

乐观读锁是先获取乐观读锁,再读数据,读完后还需要再检查刚刚读数据期间是否有写锁,若有则必须等待写锁完成后再次尝试,否则则获取读锁。

LockSupport

LockSupport 是用来创建锁和其他同步类的基本阻塞原语, 它的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程

关键方法 说明
static void park() 将当前锁阻塞
static void unpark(Thread thread) 对指定线程解除阻塞

基本使用方法:

LockSupport.park();
LockSupport.unpark(Thread)

与 Object 的 wait 方法不同,Object 的 wait 执行前需要获得 synchronized 锁,LockSupport 不需要。

锁性能比较

定义一个共享int类型变量,写线程在获取锁后对其进行累加操作,加到10^7 。 读线程获取锁后,读取变量。 下面测试不同的锁效率,表格时间单位为秒。

对int类型变量进行累加到 10^7

锁类型 5读5写 10读10写 16读4写 19读1写
synchronized 0.9 0.7 1.6 11.3
ReentrantLock 0.6 0.6 2.2 5.6
ReentrantReadWriteLock 1.9 1.9 25.4 190.7
StampedLock 0.3 0.5 0.7 3.3
StampedLock 乐观读锁 1.8 2.1 2.3
城东书院 www.cdsy.xyz
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐