重入, 中断, 公平, 读写锁

重入, 中断, 公平, 读写锁

标签(空格分隔): 操作系统


可重入锁 / 不可重入锁

可重入锁

Wikipedia: 若一个程序或子程序可以" 在任意时刻被打断然后操作系统调度之行另一端代码, 这段代码又调用了该子程序而不会出错 " 则称其为可重入锁. 即当该子程序正在运行时, 执行线程可以再次进入并执行它, 仍然获得符合设计时的预期结果. 与多线程并发执行的线程安全不同, 可重入强调对单个线程执行时重新进入同一个子程序仍然是安全的.

某个线程试图获取一个已经由他自己持有的锁. 这个请求可以成功, 那么此时的锁就是可重入锁, 重入锁的这种机制也说明了它是以 "线程" 为粒度获取锁, 而不是以"调用"为粒度.

重入锁一个常见的实现方式是, 为每一个锁关联一个持有者和持有计数值, 当计数值为0时, 这个锁会被认为没有被任何线程持有, 当线程请求一个未被持有的锁的时候, JVM会把这个锁给这个线程, 并记下这个锁的持有者, 同时计数器值置为1, 如果同一个线程再次获取这个锁, 计数值递增一. 当线程同步代码块时, 计数值将递减一, 当为0时, 锁被释放. 常见的重入锁有SynchronizedReenTrantLock

不可重入锁

不可重入锁和可重入锁相反, 就是同一个线程多次请求同一把锁就会出现死锁. 可以看到父类和子类的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();
    }
}

现在模拟一个不可重入的自旋锁.

posted @ 2020-04-10 15:37  X-POWER  阅读(231)  评论(0编辑  收藏  举报