ReentrantLock—重入锁
建议应用的同步方式,相对效率比synchronized高。量级较轻
和synchronized功能相似
Lock():加锁,后边的代码被当前锁对象锁定,直到调用unlock()方法
unlock():解锁
tryLock()–不发生阻塞:尝试锁,如果有锁,无法获取锁标记,返回false;如果获取锁标记,返回true
尝试锁在解除锁标记的时候,一定要判断是否获取到锁标记,如果当前线程没有获取到锁标记,会抛出异常。
tryLock( s) :阻塞尝试锁,阻塞参数代表的时长,尝试获取锁标记,如果超时,不等待,直接返回
lockInterruptibly():可以尝试打断的阻塞状态,阻塞等待锁,可以被其他的线程打断阻塞状态
当一个线程想要获取另一个线程的锁标记的时候,调用lockInterruptibly()方法可以阻塞等待另一个线程执行完成释放锁标记之后获取锁,这种阻塞状态下,可以通过调用Thread类的interrupt()来打断当前线程的休眠或者阻塞状态,但是会抛出异常。
无法通过interrupt()来打断通过lock()方法获取锁标记的线程,可以打断通过lockInterruptibly()获取锁标记的线程。
不公平锁:默认创建的ReentrantLock锁对象就是不公平锁机制,当多个线程阻塞等待获取锁标记的号死后,当锁释放,cpu会让其他线程抢夺锁,谁先抢到谁执行。
公平锁:通过创建ReentrantLock对象的时候构造方法传入一个true,表示当前锁是公平锁,公平锁会记录线程的等待时长,等待时间最长的线程,当锁释放的时候优先获取锁
使用重入锁必须手动释放锁标记,一般在finally中执行。
synchronized没有公平性
阻塞状态
:包括普通阻塞,等待阻塞,锁池队列。
- 普通阻塞:sleep(1000),可以被打断,调用Thread类的interrupt()方法 ,可以打断阻塞状态,抛出异常。
- 等待队列:wait()方法被调用,也是一种阻塞状态,只能由notify()唤醒。无法打断。
- 锁池队列:无法获取锁标记的时候。不是所有的锁池队列都可被打断
使用ReentrantLock的lock方法,获取锁标记的时候,如果需要阻塞等待锁标记,无法被打断
使用ReentrantLock的lockInterruptibly方法,获取锁标记的时候,如果需要阻塞等待的时候,可以被打断。
Condition–条件
为Lock增加条件,当条件满足时,做什么事情,如加锁或解锁
ReetrantLock+Condition实现生产者消费者模型
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestProAndCon {
LinkedList<Object> list = new LinkedList<>();
private final int MAX_SIZE=10;
Lock lock = new ReentrantLock();
//生产者条件
Condition producer = lock.newCondition();
//消费者条件
Condition consumer = lock.newCondition();
public void put(Object o){
lock.lock();
while (list.size()==MAX_SIZE){
//当队列中元素的个数达到最大
try {
//生产者线程进入等待队列
System.out.println("生产等待。。。");
//借助条件,生产者进入等待队列,释放锁
producer.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
list.add(o);
consumer.signalAll();
}finally {
lock.unlock();
}
}
public Object get(){
lock.lock();
Object o = null;
while (list.size()==0) {
//当队列中的元素个数为0时
//消费者线程进入等待队列
try {
System.out.println("消费者等待...");
//借助条件使消费者进入等待
consumer.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
o = list.removeFirst();
//借助条件,使生产者全部唤醒
producer.signalAll();
}finally {
lock.unlock();
}
return o;
}
public static void main(String[] args) {
TestProAndCon t = new TestProAndCon();
for (int i = 0 ; i<10 ;i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 5; j++)
System.out.println(t.get());
}
}, "consumer" + i).start();
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0 ; i<2 ; i++){
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0;j<25;j++){
t.put("container value="+j);
}
}
}).start();
}
}
}