前言
在Java5.0之前,在协调对共享对象的访问时可以使用的机制只有synchronized和volatile。Java5.0增加了一种新的机制:ReentrantLock。ReentrantLock并不是一种替代内置加锁的方法,而是当内置锁机制不适用时,作为一种可选择的高级功能。
Lock与ReentrantLock
与内置加锁机制不同的是,Lock提供了一种无条件的、可轮询的、定时的以及可中断的锁获取操作,所有加锁和解锁的方法都是显示的。如下是Lock接口:
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
ReentrantLock实现了Lock接口,并提供了与synchronized相同的互斥性和内存可见性。
ReentrantLock的简单使用
public static void main(String[] args){
ReentrantLock lock = new ReentrantLock();
lock.lock();//获取锁
try {
//do something
}finally {
lock.unlock();//释放锁
}
}
在finally块中释放锁,是为了保证在获取到锁后,锁最终能够被释放。
不要将获取锁的过程写在try块中,因为如果在获取锁(自定义锁的实现)时发生了异常,异常抛出的同时,也会导致锁无故释放。
锁的重进入
重进入是指任意线程在获取到锁之后能够再次获取该锁而不会被锁所阻塞。线程n次获取了锁,就需要n次释放锁,这样才能保证其它线程有机会获取锁,不然的话线程会一直在阻塞等待获取锁。
public static void main(String[] args){
ReentrantLock lock = new ReentrantLock();
lock.lock();//获取锁
lock.lock();//获取锁
try {
//do something
}finally {
lock.unlock();//释放锁
lock.unlock();//释放锁
}
}
中断响应
与synchronized锁相比,Lock的lockInterruptibly方法能够在获取锁的同时保持对中断的响应。
/**
* 线程的中断
*
* 1:public void interrupt() 中断线程
* 2:public boolean isInterrupted() 判断是否被中断
* 3:public static boolean interrupted() 判断是否被中断,并清除当前中断状态
*/
class MyThread1 implements Runnable{
@Override
public void run() {
// System.out.println(Thread.currentThread().getName()+" thream is running...");
while (true) {
if (Thread.currentThread().isInterrupted()) {//如果这个注释了的话,thread.interrupt();没作用
System.out.println("线程被中断了...");
break;
}
System.out.println("thream is running...");
}
}
}
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new MyThread1());
thread.start();
Thread.sleep(100);
thread.interrupt();
}
}
定时锁
定时锁可以避免发生死锁时线程一直处于阻塞状态,从而使线程提前结束。
public class TryLockMain {
ReentrantLock lock = new ReentrantLock();
public void methodA() throws InterruptedException {
try{
if (lock.tryLock(2,TimeUnit.SECONDS)){
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+" methodA run...");
}else {
System.out.println(Thread.currentThread().getName()+" get lock fail...");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//查询当前线程是否保持此锁定
if (lock.isHeldByCurrentThread()){
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
TryLockMain main = new TryLockMain();
new Thread(new Runnable() {
@Override
public void run() {
try {
main.methodA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
main.methodA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
公平锁和非公平锁
在公平的锁上,线程将按照请求的顺序来获得锁;在非公平的锁上,线程将会随机获得锁。
//false 非公平锁;true 公平锁
ReentrantLock lock = new ReentrantLock(false);