重入锁 reentrantLock和synchronized关键字相比的优势是他更加灵活,可以在任何需要的地方加锁或者释放锁。下面用这两种方式进行同步控制。
//使用重入锁
public void run() {
for (int j = 0; j < 100000; j++) {
//lock为ReentrantLock的一个实例
lock.lock();
try {
i++;
} finally {
lock.unlock();
}
}
}
//使用synchronized关键字
public void run() {
for (int j = 0; j < 100000; j++) {
synchronized(lock){
i++;
}
}
两者都能在多线程的情况下保证数据的原子性,但是显然重入锁的方式更加灵活。此外重入锁可以响应中断,看下面的例子。
首先我们实例化两个重入锁类变量lock1,lock2,然后用线程1先获得lock1的锁,再获得lock2的锁。线程2则先获得lock2的锁再获得lock2的锁。这样会导致死锁。此时我们可以中断线程2,使得线程2释放lock2,并退出,而线程1可以获得lock2的锁。这就体现了重入锁的一个优点:响应中断。
//测试代码
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by owen on 2017/3/10.
*/
public class IntLock implements Runnable {
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lock;
public IntLock(int lock){
this.lock = lock;
}
@Override
public void run(){
try{
if(lock ==1) {
lock1.lockInterruptibly();
Thread.sleep(500);
lock2.lockInterruptibly();
}
else{
lock2.lockInterruptibly();
Thread.sleep(500);
lock1.lockInterruptibly();
}
}catch (InterruptedException e){
e.printStackTrace();
}finally {
if(lock1.isHeldByCurrentThread()){
lock1.unlock();
}
if(lock2.isHeldByCurrentThread()){
lock2.unlock();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getId()+"线程退出");
}
}
public static void main(String[] args) throws InterruptedException {
IntLock l1 = new IntLock(1);
IntLock l2 = new IntLock(2);
Thread t1 = new Thread(l1);
Thread t2 = new Thread(l2);
t1.start();
t2.start();
Thread.sleep(4000);
t2.interrupt();
}
}
注意到重入锁申请获得锁的方式是使用lockInteruptibly()方法而不是方法,这是因为lockInteruptibly()方法优先响应中断而不是优先申请锁。而lock()方法则相反。
文档里面对lockInteruptibly()方法的一个说明是这样的:
In this implementation, as this method is an explicit interruption point, preference is given to responding to the interrupt over normal or reentrant acquisition of the lock.
待续。
来源:https://www.cnblogs.com/owen-7/p/6530868.html