Java多线程(四)

Lock的使用

前言


这是java多线程基础理论知识的第6篇文章,预计这一系列的分享还有2篇。今天要分享的内容是进阶版的线程锁,之前的线程锁主要是synchronized关键字的方法或者语句块,这种用法比较生涩和不友好;本章推荐使用Lock对象来替换synchronized,因为Lock类有很多独特的优势,而且还有助于学习并发包中的源码。

主要内容如下:

大纲

ReentrantLock类

ReentrantLock

声明方式如下:

private Lock lock = new ReentrantLock();

使用方式如下:

//程序片段

try{
    //获得锁
    lock.lock();
    ...

}catch(InterruptedException e){
    e.printStackTrace();
}finally {
    //释放锁
    lock.unlock();
}

调用lock.lock()代码的线程就持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢。和synchronized关键字一样,线程简间的执行顺序是随机的。

Conditon的使用

关键字synchronized与wait()和notify()/notifyAll()方法相结合可以实现等待/通知模式。类ReentrantLock也具有相同的功能,但需要借助Condition对象,该对象支持多路通知功能,就是在一个Lock对象里可以创建多个Condition(对象监视器)实例,线程对象可以注册在指定的Condition中,从而可以有选择地进行线程通知,在线程调度上更加灵活。

声明方式如下:

private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();

使用方式如下:

try{
    
    lock.lock();
    ...
    //等待
    condition.await();
    ...

}catch(InterruptedException e){
    e.printStackTrace();
}finally {
    lock.unlock();
}

注意,在condition.await()和condition.signal()方法调用前必须调用lock.lock()方法获得同步监视器。

总结:

  1. Object类中的wait()(代码行处释放锁)方法相当于Condition类中的await()方法。
  2. Object类中的wait(long timeout)方法相当于Condition类中的await(long time,TimeUnit unit)方法。
  3. Object类中的notify()(执行完释放锁)方法相当于Condition类中的signal()方法。
  4. Object类中的notifyAll()方法相当于Condition类中的signalAll()方法。
公平锁与非公平锁
Lock锁
公平锁
非公平锁
FIFO
抢占机制

  • FIFO:先来先得,先进先出。
  • 抢占机制:随机获得锁。

使用方式(true为公平锁,false为非公平锁):

lock = new ReentrantLock(boolean)

公平锁的执行结果是呈基本有序的,不是完全有序;非公平锁的执行结果是基本乱序的。

方法大总结

这里用表格列举一下,lock经常使用的方法。

方法名参数描述
getHoldCount/查询当前线程保持此锁定的个数,也就是调用lock()方法的个数。
getQueueLength/返回正等待获取此锁定的线程估计数。
getWaitQueueLengthCondition等待与此锁定相关的给定条件Condition的线程估计数 。
hasQueuedThreadThread查询指定的线程是否等待获取此锁。
hasQueuedThreads/查询是否有线程等待获取此锁。
hasWaitersCondition查询是否有线程正在等待与此锁有关的Condition条件。
isFair/判断是不是公平锁 ,ReentrantLock默认使用非公平锁。
isHeldByCurrentThread/查询当前线程是否保持此锁定。
isLocked/查询此锁定是否由任意线程保持。
lockInterruptibly/如果当前线程未被中断,则获取锁定;如果中断则抛出异常。
tryLock/仅仅在调用时锁定未被另一个线程保持的锁。
tryLocklong,TimeUnit如果锁在给定的时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。
awaitUninterruptibly/忽略中断的await方法,不抛出异常。
awaitUntil时间戳线程在等待时间到达前,可以被其他线程提前唤醒的await方法。
ReentrantReadWriteLock类

ReentrantLock类具有完全互斥的效果,即同一时间只能有同一个线程在执行ReentrantLock.lock()方法后面的任务。这样做虽然很安全,但是效率很低下,这里介绍一种读写锁ReentrantReadWriteLock类,读写锁表示有两个锁,一个是读相关操作的锁,也称共享锁;一个是写相关操作的锁,也称排他锁。

共享锁声明方式如下:

lock.readLock().lock()

lock.readLock().unlock()

排他锁声明方式如下:

lock.writeLock().lock()

lock.writeLock().unlock()

读读共享

共享锁允许多个线程同时执行lock()方法后面的代码。

写写互斥

互斥锁同一时间只允许一个线程执行lock()方法后面的代码。

读写互斥

读写操作是互斥的,读完之后才能写。

写读互斥

写读操作是互斥的,写完之后才能读。只要出现写操作锁,就都是互斥的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值