True或False:锁之于同步块就像goto之于结构化编程一样



这是一个公平的类比吗?我想我可以想到一些场景,你可以使用锁,但我不确定它们是否必要。

例如,下面是我最近编写的一个循环,用于等待线程更新列表。我很抱歉,如果这是可怕的java,因为我是一个本地的linux内核:
ReentrantLock lock;
...
while(true) {
    lock.lock();
    int size = queue.size();
    if (size == 0) {
        try {
            lock.unlock();
            Thread.sleep(3600000);
            continue;
        } catch (InterruptedException e) {
            lock.lock();
            size = queue.size();
            if (size == 0) {
                lock.unlock();
                continue;
            }
        }
    }
    VPacket p = queue.getFirst();
    lock.unlock();
    return p;
}

其中VPacket是我正在编写的特定协议的数据包。

当我思考Collections.synchonizedList class时,这个类比出现在脑海中,思考如何在没有这种类似c的技巧的情况下做到这一点。

同步块比ReentrantLock这样的类早很多年;该包中的类被引入,以提供一些比Java语言先前提供的更复杂、更高级的功能——尽管其中许多功能仅在非常特殊的情况下才需要。

但是在这个特定的情况下,我会说使用同步块(并且等待(N)而不是睡眠(N)!)会更优雅。我理解你的比喻,我想说有时是成立的;当然,对于这种普通的情况,使用同步块就像在c++中使用RAII模式一样——这是确保在需要时清理东西的最清晰的方法。

一般来说,设计行为(和执行)良好的并发数据结构是一项非常棘手的任务。如果您不使用低级工具自己实现所有的东西,而是使用标准库中可用的更高级的抽象,这被认为是一件好事(tm)。

对于您的任务,我宁愿使用BlockingQueue或BlockingDeque来为我处理同步

同步块本质上总是正确嵌套的,而您可以误用锁而忘记解锁。然而,你读到的关于锁的第一件事是总是在try/finally结构中使用它们,像这样:

lock.lock();
try {
    // Do things...
}
finally {
    lock.unlock();
}

这是一个强烈推荐的模式,确保你的锁像同步块一样工作。

锁与同步块相比有以下几个优点:

    它们比同步块更有效,尽管我读到在最近的JVM中已经修复了这个问题。为了提高并发性,一些锁可以分为读锁和写锁。
  • 它们可以被传递,但这样就脱离了上面解释的安全模式。

所以,我的意思是,锁更像是一把更大的枪:更强大,但如果你不知道如何使用它们,也会更危险。

相同代码的修改版本,更优化的IMO:)回答你的问题,类比是错误的。Gotos的名声很差,因为他们允许控制流逃逸,导致噩梦。锁在同样的意义上不允许控制逃逸。你可能会问,如果我获得了一个锁却拒绝释放它会发生什么。同步块是不可能的。理想的模式是使用try-finally。顺便说一句,并发编程本身就是一场噩梦,无法增强或减少。

while(true) {
    if(queue.size()==0){
        Thread.sleep(36000);
    }
    lock.lock();
    Vpacket p = null;
    try {
         p = null;
         if(queue.size()!=0) {
              p = queue.pop();
         }
    } finally {
         lock.unlock();
         if(p!=null) {
              return p;
         }
    }
}

最新更新