代码之家  ›  专栏  ›  技术社区  ›  Adelin

在Java中解锁一个被多次锁定的对象需要多少次解锁操作?

  •  1
  • Adelin  · 技术社区  · 6 年前

    阅读java语言规范-我可以在这段语句中获取内存模型。

    线程t可以多次锁定特定的监视器;每次解锁 反转一次锁定操作的效果。

    然后我用下面的代码尝试了一下,但是似乎不起作用。 要么我不明白这句话,要么我的代码没有按我想的做。。。

    public class MultipleLocks {
    
    
    private static final Object LOCK = new Object();
    
    public static void main(String[] args) throws InterruptedException {
    
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                synchronized (LOCK) {
                    //some code ...
                }
            }
    
    
            synchronized (LOCK) {
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    
        t1.start();
    
        Thread t2 = new Thread(() -> {
    
            synchronized (LOCK) {
                System.out.println("I can acquire a lock !");
            }
        });
    
        t2.start();
    
        synchronized (LOCK) {
            LOCK.notify();
        }
    
        }
    
    
    }
    

    11-锁 只解锁一次?

    代码显示只需要一个锁操作,或者我遗漏了什么?

    编辑:

    如果我的代码是错误的,我怎样才能模拟n次获取锁并n次释放它,如果n-1次被释放,那么线程应该继续锁定锁?

    2 回复  |  直到 6 年前
        1
  •  1
  •   LuCio    6 年前

    你的问题“ 代码显示只需要一个锁操作,或者我遗漏了什么? “得到了皮特·柯克汉姆的回答。

    主要问题的答案” 在Java中解锁一个被多次锁定的对象需要多少次解锁操作? “就是你引用的那个。

    下面的代码显示了如何 Thread t1 " 多次锁定特定监视器 “还有那个” 每次解锁都会逆转一次锁定操作的效果 ".

    螺纹t1 进入 synchronize 封锁三次。每次 使同步 块被输入一个(附加的)锁被获取。每次 使同步 锁被释放了。因此,先 t1 全部留下 使同步 阻碍 Thread t2 可以输入 使同步 封锁。

    public class Locking {
    
        private static Object o = new Object();
    
        public static void main(String[] args) throws InterruptedException {
    
            Thread t1 = new Thread(Locking::lockSeveralTimes);
            Thread t2 = new Thread(Locking::lockOnce);
            t1.start();
            Thread.sleep(100); // give t1 some time to start
            t2.start();
        }
    
        protected static void lockOnce() {
            synchronized (o) {
                System.out.println("DONE");
            }
        }
    
        protected static void lockSeveralTimes() {
            try {
                System.out.println("Has Lock: " + Thread.holdsLock(o));
                synchronized (o) {
                    System.out.println("Aquired Lock: " + Thread.holdsLock(o) + " / Times: " + getLockedMonitorsCount());
                    waitOneSecond();
                    synchronized (o) {
                        System.out.println("Aquired Lock: " + Thread.holdsLock(o) + " / Times: " + getLockedMonitorsCount());
                        waitOneSecond();
                        synchronized (o) {
                            System.out.println("Aquired Lock: " + Thread.holdsLock(o) + " / Times: " + getLockedMonitorsCount());
                            waitOneSecond();
                            System.out.println("Going to release lock. Still holds: " + Thread.holdsLock(o) + " / Times: " + getLockedMonitorsCount());
                        }
                        waitOneSecond();
                        System.out.println("Going to release lock. Still holds: " + Thread.holdsLock(o) + " / Times: " + getLockedMonitorsCount());
                    }
                    waitOneSecond();
                    System.out.println("Going to release lock. Still holds: " + Thread.holdsLock(o) + " / Times: " + getLockedMonitorsCount());
                }
                System.out.println("Still holds: " + Thread.holdsLock(o));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        protected static void waitOneSecond() throws InterruptedException {
            Thread.sleep(1000);
        }
    
        protected static int getLockedMonitorsCount() {
            return ManagementFactory.getThreadMXBean().getThreadInfo(new long[] { Thread.currentThread().getId() }, true, false)[0].getLockedMonitors().length;
        }
    
    }
    

    输出为:

    Has Lock: false
    Aquired Lock: true / Times: 1
    Aquired Lock: true / Times: 2
    Aquired Lock: true / Times: 3
    Going to release lock. Still holds: true / Times: 3
    Going to release lock. Still holds: true / Times: 2
    Going to release lock. Still holds: true / Times: 1
    Still holds: false
    DONE
    

    使用JDK 8为我运行。

        2
  •  2
  •   Pete Kirkham    6 年前

    此代码不会对对象的状态执行任何操作:

        for (int i = 0; i < 10; i++) {
            synchronized (LOCK) { // lock gained on LOCK object
                //some code ...
            } // lock released on LOCK object
        }
    

    锁在同步块开始时获得,在结束时释放。这样做十次会使对象处于与循环开始时相同的状态。

    然后,Thread1获取锁,然后等待,这导致它释放锁,直到另一个线程通知对象。

    线程释放此监视器的所有权并等待另一个监视器 线程通知等待此对象监视器唤醒的线程 Object.wait() javadocs

    线程2获取锁,打印程序的唯一输出,然后释放锁。

    主线程获取一个锁,通知一个等待的线程,然后释放锁。

    因此,线程可以按照几个顺序获取锁,所有这些顺序都会导致相同的输出。