JAVA并发编程梳理与学习六(Lock和Condition 接口)

一、Lock
被称为显示锁。既然已经有synchronized为什么还要定义Lock呢?使用过synchronized关键字获取锁的都知道,synchronized获取锁和释放锁太死板,有以下缺点。
一旦一个线程用synchronized获取锁,别的竞争锁的线程都要处于等待状态,除非该线程执行完锁定代码或者线程抛出异常释放锁,别的等待线程才有重新竞争锁的机会。
所以会出现下面问题:一旦拿到锁的线程,如果由于线程调用不释放锁的阻塞方法或者该线程要处理的业务耗时较长,那么其他线程只能处于等待状态,这样会影响程序执行效率。所以为了解决这些问题,更加灵活的获取和释放锁,Lock应运而生。
Lock有一下优势
1.可以超时获取锁:在指定时间之内获取锁,如果在这个时间之内没有获取锁,则结束等待状态;
2.能被中断的获取锁:我们知道synchronized除非我们手动通过interrupted或者isInterrupted去判断中断状态,线程才能响应中断,在等待获取锁的过程中是不能响应中断的。Lock则不同,正在等待获取锁的线程能响应中断,当获取锁的线程被中断时,中断异常将会被抛出。
3.尝试非阻塞的获取锁:当前线程尝试获取锁,如果锁处于空闲状态,立马获取锁,如果获取不到也不会处于一直等待状态
二、Lock标准用法及注意事项

lock.lock();
try{
  count++;//逻辑代码
}finally{
lock.unlock()
}

注意:一定要在finally里面释放锁,因为要是在逻辑代码下面释放锁,如果逻辑代码报错,锁有可能得不到释放,写在finally里面是为了保证获取锁后能最终释放
三、Lock常用api
在这里插入图片描述
四、ReentrantLock
我们知道Lock是java一个接口,要使用的话必须用它的实现类,ReentrantLock就是Lock一个常用实现类,ReentrantLock称为可重入锁。什么是可重入锁,就是一个线程已经获取到了该锁,还可以重复申请该锁的使用权。比如我们对一个递归方法加锁,如果不支持可重入,那么递归方法将无法进行下去,因为第一拿到锁后还没释放,其他所有线程都拿不到该锁。synchronized隐式的支持可重入,ReentrantLock也是支持可重入
五、公平锁和非公平锁
公平锁:顾名思义这个锁是公平的,意思就是先申请获取锁的线程,当锁被释放后一定会先拿到锁,也就是等待时间长的线程优先获取锁,锁按时间顺序获取
非公平锁:和公平锁相反,等待时间最长的线程可能不会优先获取锁。比如,现在A、B、C3个线程在等待获取锁,我们知道,当锁释放的时间,cpu要重新进行上下文切调度等待获取锁的线程去获取锁,这个时间线程D突然来了,要申请锁,那么就能马上获取到锁,而不管A、B、C线程,这就是非公平锁。
比较:从上面分析可以看出,显然非公平锁的效率是高于公平锁的。假设在进行上下文切换时间,线程D完成获得、使用以及释放这个锁,这样一来A并没有延迟获取锁,B也完成了自己的任务。
ReentrantLock提供了一个构造函数,能够控制锁是否是公平的,默认是非公平的
六、读写锁ReadWriteLock和ReentrantReadWriteLock
ReadWriteLock是接口,ReentrantReadWriteLock是ReadWriteLock的实现类,可以看ReadWriteLock接口源码定义获取读锁和写锁的方法
在这里插入图片描述
**这么做的好处和体现的思想:**读写分离的思想。我们知道多线程之所以发生线程不敢全问题,主要是多个线程共同改变一个共享变量,一般读是不会发生线程安全问题的,而无论是synchronized还是上面的ReentrantLock都是排他锁,在同一时间只允许一个线程访问,别的线程只能处于等待状态。假如我们现在有一个读多写少的操作,如果使用排他锁,无论是读还是写都只能同一时间一个进行,其实我们想过没有读操作是可以同时进行的,这样是不是能极大提高读的速度。ReentrantReadWriteLock就给我们提供了这种机制。
工作时2个锁的互斥状态:写独占,读共享,读写互斥。写独占,一个线程拿到读锁,其他所有线程全部处于等待状态;读共享,一个线程拿到写锁,其余读的线程都可以继续工作,但是写锁处于等待状态(读写互斥);
七、condition接口
condition接口作用:我们仔细看Lock接口下面方法可以看到 Condition newCondition()方法,通过这个方法可以获取Condition。Condition作用是什么呢?我们知道,我们使用synchronized关键字实现锁时间,会有Object的一组监视器方法wait()/wait(long timeout)/notify()/notifyAll()方法,这些方法和synchronized关键字使用可以实现等待/通知机制。而Condition也提供了类似Object类似于这些作用的方法,可以和Lock配合使用实现等待/通知机制
常用方法解读
在这里插入图片描述
使用模板

Lock lock=new ReentrantLock();
Condition condition=lock.newCondition();
public void conditionWait() throws InterruptedException{
  lock.lock();
        try{
            condition.await();
        }finally {
            lock.unlock();
        }
}

public void conditionSignal() throws InterruptedException{
  lock.lock();
        try{
            condition.signal();
        }finally {
            lock.unlock();
        }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章