1:概览
- 重入锁完全可以代替synchronized
lock()
方法显示加锁unlock()
方法显示释放锁- 要注意的是lock()获取锁的方法无法响应中断
可以指定合适加锁和合适释放锁,比较灵活
支持重入
重入锁也是支持重入的,但是仅限于已获得该锁的那一个线程
lock.lock();
lock.lock();
一些操作
lock.unlock();
lock.unlock();
注意加锁了几次就要释放锁几次
- 如果释放的次数少了
- 相对于当前线程还持有该锁,其他线程无法获得该锁
- 如果释放次数多了
- 相对于没有获得锁就释放锁,会抛出异常
2:中断响应
这是比起synchronized来说一个比较独特的功能。
使用synchronized时,如果等待一个锁就必须一直等待下去。如果发生死锁等等就无法解决。
但是重入锁在等待获得锁的时候提供了可以被中断的能力
lockInterruptibly()方法
:这是一个可以对中断进行响应的锁申请操作,即在锁等待的过程中,可以响应中断。会将中断标志位复位
import java.util.Scanner;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
public static void main(String[] args) throws InterruptedException {
th t=new th();
Thread t1=new Thread(t, "t1");
Thread t2=new Thread(t, "t2");
t1.start();
Thread.sleep(1000);
t2.start();
t2.interrupt();
Thread.sleep(1000);
System.out.println(t2.isInterrupted());
}
}
class th implements Runnable{
ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
try {
lock.lockInterruptibly();
System.out.println(Thread.currentThread().getName()+"获得锁了,");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
System.out.println(Thread.currentThread().getName()+"释放锁");
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"申请锁等待的时候响应中断,不执行了。");
}
}
}
》》》》》》》》》》》》
t1获得锁了,
t2申请锁等待的时候响应中断,不执行了。
false
t1释放锁
t1先获得该锁,并且持有一段时间,这时候t2线程开启也去申请该锁,由于t1申请,就只能等待该锁,这时候对t2进行中断,由于使用的是lockInterruptibly()方法,等待锁的时候可以被中断,这时候t2被中断了就响应中断,而不会再去等待该锁了
3:锁申请等待限时
- 锁等待的时候有一个时间限制,超过了这个时间就不再申请锁了
- 使用
tryLock()
方法,在时间限制内获得锁返回true,否则返回false - 如果不带参数,等待时间就是0,尝试获取锁失败就不再等待锁
- 而且也是可以响应中断的!
import java.sql.Timestamp;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
public static void main(String[] args) throws InterruptedException {
th t=new th();
Thread t1=new Thread(t, "t1");
Thread t2=new Thread(t, "t2");
Thread t3=new Thread(t, "t3");
t1.start();
Thread.sleep(1000);
t2.start();
t3.start();
Thread.sleep(1000);
t3.interrupt();
}
}
class th implements Runnable{
ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
try {
if(lock.tryLock(5, TimeUnit.SECONDS)){
System.out.println(Thread.currentThread().getName()+"获取锁成功");
Thread.sleep(10000);
lock.unlock();
System.out.println(Thread.currentThread().getName()+"释放锁");
}else{
System.out.println(Thread.currentThread().getName()+"没有获取到该锁");
}
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"被中断了");
}
}
}
---------------
t1获取锁成功
t3被中断了
t2没有获取到该锁
t1释放锁
这段代码很好地展示了限时等待锁的情况,而且也说明了这种方法去申请锁也是能在等待过程中被中断的。
4:公平锁
- 重入锁默认是非公平锁
- 但是可以设置为公平锁
new ReentrantLock(true);
- 公平锁就是==按照时间地顺序,先到先得
- 公平锁很好地避免了饥饿
- 但是公平锁要维护一个有序队列,开销大,性能低下
- 当锁可用时,几个线程都在申请该锁,非公平锁会随机让一个线程获得该锁,而公平锁是让有序对列排头地线程获得锁。注意公平锁与i非公平锁针对地是请求锁,而不是线程间通信的等待和唤醒
5:重入锁的好搭档-Condition
object.wait()与object.notify()
是与synchronized配合使用- condition与重入锁相配合使用
- 通过一个重入锁lock,调用
lock.newCondition()
可以得到一个与该重入锁相关联的condition对象