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

Java:允许人们通过大门的程序

  •  -1
  • mattsmith5  · 技术社区  · 2 年前

    我正在编写一个程序,对5号门进行计数,然后允许人们进入大楼(通过执行System.out.println)。

    我有以下解决方案,使用synchronized。然而,有人提到,对于排队的人来说,这种解决方案不允许顺序锁定公平性。我该如何重写以允许它?下面的信号量正确吗?

    使用同步:

    public class LineCount {
    
        int totalInLine = 0;
    
        public synchronized void addToLine() {
            totalInLine = totalInLine + 1;
            if (totalInLine == 5) {
                 System.out.println("People may enter");
                 totalInLine = 0;
            }
        }
    

    使用信号量:

    public class LineCount {
    
        Semaphore semaphore = new Semaphore(5, true);
    
        public void addToLine() throws InterruptedException {
    
            semaphore.acquire();
            if (semaphore.availablePermits() == 0) {
                System.out.println("People may enter");
                semaphore.release(5);
                semaphore = new Semaphore(5, true);
            }
        }
    }
    
    1 回复  |  直到 2 年前
        1
  •  1
  •   Solomon Slow    2 年前

    这个 Semaphore 版本与 synchronized 版本但是 信号量 版本不是线程安全的。我建议两个改变:

    public class LineCount {
    
        final Semaphore semaphore = new Semaphore(5, true);   // added `final` keyword
    
        public void addToLine() throws InterruptedException {
            semaphore.acquire();
            if (semaphore.availablePermits() == 0) {
                System.out.println("People may enter");
                semaphore.release(5);
             // semaphore = new Semaphore(5, true);           // **Don't Do This**
            }
        }
    }
    

    原因是,如果某个线程A执行 semaphore.release(5) 语句,则线程B可以滑入,并递减 老的 线程A之前的信号量 semaphore = new Semaphore(...) 转让生效。这将允许在下次打印消息之前打五个以上的电话。

    没有必要创建新的信号量,因为每个 release(5) 呼叫将允许另外五个呼叫获得许可。

    的原因 final 主要是为了确保每个阅读代码的人都能立即理解 semaphore 总是指同一个对象。


    更新:

    然而,有人提到 同步的 ]对于排队的人来说,该解决方案不允许顺序锁的公平性。

    我甚至猜不出这意味着什么。你应该向“某人”寻求澄清。

    你的 同步的 的版本 addToLine 每打五个电话就会打印一条信息。它不做任何其他事情。它不会让任何来电者 等待 打印消息所需的时间比其他调用方打印消息所用的时间长。这里面的“不公平”在哪里?

    你的问题的标题是“允许人们通过大门的计划”。但这里没有真正的大门模型。里面没有任何东西能造就任何“人” 等待 让“门”“打开”。它实际上只是一个线程安全的方法,每五次调用就会打印一条特定的消息。