繁体   English   中英

最好在 try 块内有一个同步块,还是在同步块内有一个 try 块?

[英]It is better to have a synchronized block inside a try block or a try block inside a synchronized block?

例如,这样更好吗?

try {
    synchronized (bean) {
        // Write something              
    }
} catch (InterruptedException e) {
    // Write something
}

或者最好这样:

synchronized (bean) {
    try {           
        // Write something              
    }
    catch (InterruptedException e) {
        // Write something
    }
}

我想知道哪一个是最佳实践。 显然考虑到我必须同步 try 块中的所有代码。 我不是在谈论我只需要同步 try 内的部分代码的情况(在这种情况下,我认为在 try 内有同步块会更好)。 我怀疑我必须同步所有 try 块的情况。

最好在try块内部使用synchronized块或在synchronized块内部使用try块?

除非你明确需要catchsynchronized块中,否则我会使代码的synchronized部分尽可能小,并将它放在try / catch中。 所以第一种模式会更好。 然后,如果你确实需要在catch部分进行操作(比如记录异常或重新中断线程,见下文),这些就不会阻塞其他线程。

也就是说,如果synchronized块包含多行(当然通常不是一个好主意),那么我会考虑将try / catch块移动到更接近抛出异常的方法( waitnotify )。 如果使用大量的行,则存在使用大型try / catch块不正确地处理异常的风险。 在这里取决于参考框架。

另外,请确保至少记录中断的异常。 永远不要忽视它们。 您可能还想重新中断该线程:

try {
   ...
} catch (InterruptedException e) {
   // always a good pattern
   Thread.currentThread().interrupt();
   // handle the interrupt here by logging or returning or ...
}

没有最好的做法。 它只取决于您是否需要同步块内的异常处理部分。 您可能想要一个或另一个,并且应该选择使同步块最短的那个,同时仍然使代码正确且线程安全。

你似乎认为这只是一个美学问题。 事实并非如此。 这是一个功能性问题,答案取决于每个案例的要求。 每个同步块应该尽可能大,以包含需要同步的任何内容,而不是更大。

你的catch块是否同步是否重要? 既然你已经“写了一些东西”,我假设你要做一些日志记录,不需要与一个好的日志框架同步,这意味着答案可能不是

通常,您的目标应该是尽可能少地使用同步。 同步块越小,遇到问题的可能性就越小。

在这种情况下, InterruptedException只能在synchronized块中发生,您可以在其中调用waitsleepnotify

通常,最佳做法是将try/catch块放在可能引发异常的代码附近,以便很容易识别要修复的代码。

它与synchronized{try{}}try{synchronized{}}无关,但与synchronized{catch{}}synchronized{} catch{} 这实际上取决于你在catch块中做了什么。

但是,猜测一下,对于InterruptedException ,你通常应该在synchronized{}之外catch{} synchronized{}

这太旧了,但我今天正在审查一个初级同事的代码,我发现了一个与使用 Java 锁 object 相关的巨大错误,就像它是一个同步块一样。 我正在寻找一些关于 Java 同步不完美的文档,只是遇到了这个并考虑离开我的解决方案:

在同步的情况下,这真的取决于你的逻辑,因为 java 保证了锁的解放。

但是,当您使用基于 Object 的锁时,例如 java 的 ReentrantLock,您必须始终执行以下操作:

private final ReentrantLock lock = new ReentrantLock ();
void foo() {
    lock.lock();
    try {
        // Do your things
    } finally {
        lock.unlock();
    }
}

一旦你有了这个结构来确保锁释放,你可以将锁和整个 try/finally 都封装到另一个 try 中,如果你不想在锁边处理 catch 的话,或者把它放在哪里 // 如果你想做你的事情从内部处理它。

另外,请记住,java 锁并不完美,就像在任何编程语言中一样,锁类型的选择取决于底层语言,操作的关键程度(如果锁失败,有人会死,或者受控软件一百万次重试一次就行了?)和锁的性能影响。

如果您对锁一无所知,我建议您学习以下概念:

  • 监控(同步)
  • 互斥
  • 读/写锁定模式
  • 读取-复制-更新
  • 信号量(编程)

大多数时候,您真正需要的是信号量、多读单写锁或只是一个监视器,因此了解这些术语可以让您更快地搜索所需内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM