重入, 中断, 公平, 读写锁
重入, 中断, 公平, 读写锁
标签(空格分隔): 操作系统
可重入锁 / 不可重入锁
可重入锁
Wikipedia: 若一个程序或子程序可以" 在任意时刻被打断然后操作系统调度之行另一端代码, 这段代码又调用了该子程序而不会出错 " 则称其为可重入锁. 即当该子程序正在运行时, 执行线程可以再次进入并执行它, 仍然获得符合设计时的预期结果. 与多线程并发执行的线程安全不同, 可重入强调对单个线程执行时重新进入同一个子程序仍然是安全的.
某个线程试图获取一个已经由他自己持有的锁. 这个请求可以成功, 那么此时的锁就是可重入锁, 重入锁的这种机制也说明了它是以 "线程" 为粒度获取锁, 而不是以"调用"为粒度.
重入锁一个常见的实现方式是, 为每一个锁关联一个持有者和持有计数值, 当计数值为0时, 这个锁会被认为没有被任何线程持有, 当线程请求一个未被持有的锁的时候, JVM会把这个锁给这个线程, 并记下这个锁的持有者, 同时计数器值置为1, 如果同一个线程再次获取这个锁, 计数值递增一. 当线程同步代码块时, 计数值将递减一, 当为0时, 锁被释放. 常见的重入锁有Synchronized
和ReenTrantLock
不可重入锁
不可重入锁和可重入锁相反, 就是同一个线程多次请求同一把锁就会出现死锁. 可以看到父类和子类的
MethodA
方法的synchronized
持有的锁都是SuperSynObj.class
, 他们两个持有同一把锁, 如果Synchronized
不是可重入锁的话, 会在代码的的注释出 出现死锁的状况.
class SuperSynObj {
public synchronized void methodA() {
synchronized (SuperSynObj.class) {
System.out.println("Super class running");
}
}
}
class SynObj extends SuperSynObj {
@Override
public void methodA() {
synchronized (SuperSynObj.class) {
System.out.println("methodA");
try {
super.methodA(); // 不是重入锁将在 此处 出现死锁.
Thread.sleep(5000);
super.methodA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Dog {
public static void main(String[] args) {
new SynObj().methodA();
}
}
现在模拟一个不可重入的自旋锁.