锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized(重量级) 和 ReentrantLock(轻量级)等等 ) 。这些已经写好提供的锁为我们开发提供了便利。
重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。
在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁
代码演示
public class Test implements Runnable {
static Boolean flag = true;
public synchronized void get() {
System.out.println("name:" + Thread.currentThread().getName() + " get();");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
set();
}
public synchronized void set() {
System.out.println("name:" + Thread.currentThread().getName() + " set();");
}
@Override
public void run() {
if (flag){
get();
}else {
set();
}
}
public static void main(String[] args) {
Test test = new Test();
new Thread(test,"线程a").start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = false;
new Thread(test,"线程b").start();
new Thread(test,"线程c").start();
}
}
执行结果
从结果可以看出 线程a先进入了get方法 在get方法中即使休眠了2s 线程b和线程c也无法进入set方法 这里就是因为重入锁发挥了作用
因为set方法中调用了get方法 所以当线程a进入了set方法中的时候 set方法中的锁和get方法中的锁是同一把锁 此时尽管线程a休眠了 但set方法的锁也在线程a身上 所以线程b和线程c都无法进入set方法
附上ReentrantLock的代码
public class Test02 extends Thread {
ReentrantLock lock = new ReentrantLock();
public void get() {
lock.lock();
System.out.println(Thread.currentThread().getId());
set();
lock.unlock();
}
public void set() {
lock.lock();
System.out.println(Thread.currentThread().getId());
lock.unlock();
}
@Override
public void run() {
get();
}
public static void main(String[] args) {
Test ss = new Test();
new Thread(ss,"线程a").start();
new Thread(ss,"线程b").start();
new Thread(ss,"线程c").start();
}
}
使用ReentrantLock的注意点
ReentrantLock 和 synchronized 不一样,需要手动释放锁,所以使用 ReentrantLock的时候一定要手动释放锁,并且加锁次数和释放次数要一样