- 什么是ReentrantLock:
可重入的互斥锁,支持一个线程对资源的重复加锁。还支持获取锁时的的公平和非公平性选择。默认为非公平锁,因为非公平锁的开销小,而公平锁保证了FIFO原则,进行大量的线程切换,效率非常低。
重入的定义:任意线程在获取锁之后能够再次获得该锁而不会被锁阻塞
基本等同于synchronized的使用
- 为什么会有ReentrantLock:
因为内置锁无法中断一个等待获取锁的线程,也无法在请求获得一个锁的时候无限制的等待下去,而ReentrantLock可以做到
- ReentrantLock中的方法:
ReentrantLock继承自Lock。Lock接口:
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException;
void unlock();
Condition newCondition();
}
boolean tryLock(long timeout, TimeUnit unit) 方法:锁在给定的等待时间内空闲,并且当前线程未被中断,将获得锁
boolean tryLock()方法,锁在空闲状态时获得
void lockInterruptibly() throws InterruptedException方法,当前线程未被中断则获得锁
- 一个简单例子:
任务:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 模拟任务
* @author hetiantian
*/
public class LockTask implements Runnable {
private Lock lock = new ReentrantLock();
@Override
public void run() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " is running");
} finally {
lock.unlock();
}
}
}
测试类:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* ReentrantLock测试类
* @author hetiantian
*/
public class TestReentrantLock1 {
public static void main(String[] args) {
LockTask lockTask = new LockTask();
ExecutorService es = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
es.execute(lockTask);
}
}
}
执行结果:
pool-1-thread-1is running
pool-1-thread-3is running
pool-1-thread-4is running
pool-1-thread-2is running
pool-1-thread-5is running
一个一个执行,并且因为默认构造函数为非公平锁,如果一个线程在请求锁时刚好另外一个线程释放锁,那么这个线程将获得锁,而不是等待时间最长的线程获得锁。而且他的作用和内置锁(synchronized)相似,都是独占锁,一次只能有一个线程获得锁
- synchronized和ReentrantLock之间的选择
synchronized在发生异常时,会自动释放线程占有的锁,不会导致死锁现象发生
只有当内置锁不能满足需求时,才考略使用ReentrantLock
内置锁不能满足的需求:可定时的、可轮询的与可中断的锁的获取操作,公平队列,以及非块结构的锁
一般建议优先使用synchronized