对错:锁定是同步块,因为有结构化编程吗?

时间:2011-04-15 19:01:05

标签: java concurrency

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

例如,这是我最近写的一个循环,用于执行等待线程更新列表。如果这是一个糟糕的java,我很抱歉,因为我是一个原生的linux kernel-ite:

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的伎俩我怎么能做到这一点。

4 个答案:

答案 0 :(得分:3)

好吧,同步块比ReentrantLock这样的类早于许多年;引入该包中的类以提供比该语言之前提供的Java更复杂和更高级的功能 - 尽管只有在非常特定的情况下才需要这些功能。

但在这种特殊情况下,我会说使用同步块(等待(N)而不是睡眠(N)!)会更优雅。我理解你的比喻,我会说有时它持有;当然,对于这种普通的情况,使用同步块就像在C ++中使用RAII模式一样 - 这是确保在需要时清理内容的最清晰方法。

答案 1 :(得分:1)

通常,设计行为(并且执行)良好的并发数据结构是一项非常棘手的任务。如果你没有使用低级工具自己实现所有东西,而是使用标准库中提供的更高级抽象,那么它被认为是一件好事(.mm)。

对于您的任务,我宁愿使用BlockingQueueBlockingDeque来处理同步。

答案 2 :(得分:0)

同步块总是在本质上正确嵌套,而可以滥用锁定并忘记解锁。但是,你读到锁的第一件事就是总是在try / finally结构中使用它们,如下所示:

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

这是强烈推荐的模式,可确保您的锁定为同步块。

锁定比同步块有几个优点:

  • 它们比同步块更有效,尽管我读过最新的JVM中修复过的。
  • 某些锁可以拆分为读锁和写锁,以提高并发性。
  • 它们可以被传递,但是你已经超出了上面解释的安全模式。

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

答案 3 :(得分:-1)

相同代码的修改版本,更优化的IMO :)为了回答你的问题,这个比喻是错误的。由于他们允许控制流逃跑的方式,得到了一个坏名声,导致噩梦。锁不允许控制以相同的方式逃脱。那么,你可能会问,如果我获得一把锁并拒绝释放它会发生什么。同步块无法实现。理想的模式是使用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;
         }
    }
}