文章转载自:https://blog.csdn.net/u013452335/article/details/86576939
概念
可重入锁就是一个类的A、B两个方法,A、B都有获得统一把锁,当A方法调用时,获得锁,在A方法的锁还没有被释放时,调用B方法时,B方法也获得该锁。
这种情景,可以是不同的线程分别调用这个两个方法。也可是同一个线程,A方法中调用B方法,这个线程调用A方法。
不可重入锁就是一个类的A、B两个方法,A、B都有获得统一把锁,当A方法调用时,获得锁,在A方法的锁还没有被释放时,调用B方法时,B方法也获得不了该锁,必须等A方法释放掉这个锁。
可重入锁
在java 中,synchronized和java.util.concurrent.locks.ReentrantLock是可重入锁。
问:当一个线程获得当前实例的锁lock,并且进入了方法A,该线程在方法A没有释放该锁的时候,是否可以再次进入使用该锁的方法B?
答:不可重入锁:在方法A释放锁之前,不可以再次进入方法B 可重入锁:在方法A释放该锁之前可以再次进入方法B
测试:
public class Lock {
private boolean isLock = false;
public void lock() throws InterruptedException{
while(isLock){
wait();
}
isLock = true;
}
public void unLock(){
isLock = false;
}
}
/**
* 可重入锁
*/
public class RennerLock {
private boolean isLock = false;
Thread thread = null;
public void lock() throws InterruptedException{
Thread currentThread = Thread.currentThread();
while(isLock && thread != currentThread){
wait();
}
isLock = true;
thread = currentThread;
}
public void unLock(){
isLock = false;
}
}
测试
public class Test {
RennerLock lock = new RennerLock();
// Lock lock = new Lock();
void read()throws InterruptedException{
lock.lock();
System.out.println("read...");
read1();
lock.unLock();
}
private void read1() throws InterruptedException {
lock.lock();
System.out.println("read1...");
lock.unLock();
}
public static void main(String[] args) {
try {
new Test().read();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。ReentrantLock和synchronized都是可重入锁
synchronized:因为是自动加锁解锁,所以也注意不到这个说法(也就是嵌套的话,也不会死锁)
ReentrantLock:下面代码
private static final Lock lock = new ReentrantLock();// 非公平的,有参的是可以相对公平的
public static void needLock(){
try {
lock.lock();
TimeUnit.SECONDS.sleep(1);
methodB();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
private static void methodB() {
try {
lock.lock();
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
needLock();
}
参考:https://www.jianshu.com/p/4b45f9a1f7d2
ReentrantLock是互斥排他锁,同一时间只能有一个线程在执行任务,ReentrantLock支持锁的重入功能,虽然保证了线程的安全性,但是效率不高,实际上应该是写操作互斥,读操作共享。而jdk提供了读写锁ReentrantReadWriteLock
这里只展示读写互斥
static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public static void read() {
try {
lock.readLock().lock();
System.out.println(Thread.currentThread().getName() + " start");
Thread.sleep(10000);
System.out.println(Thread.currentThread().getName() + " end");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
public static void write() {
try {
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName() + " start");
Thread.sleep(10000);
System.out.println(Thread.currentThread().getName() + " end");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
read();
}
});
t1.setName("t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
write();
}
});
t2.setName("t2");
t1.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}