当前位置:  开发笔记 > 编程语言 > 正文

在Java关键部分中,我应该同步什么?

如何解决《在Java关键部分中,我应该同步什么?》经验,为你挑选了4个好方法。

在Java中,在代码中声明关键部分的惯用方法如下:

private void doSomething() {
  // thread-safe code
  synchronized(this) {
    // thread-unsafe code
  }
  // thread-safe code
}

几乎所有的块都同步 this,但是有什么特别的原因吗?还有其他可能吗?是否有关于同步对象的最佳实践?(比如私人实例Object?)



1> Jared..:

正如早期的回答者所指出的那样,最佳做法是在有限范围的对象上进行同步(换句话说,选择你可以使用的最严格的范围,并使用它.)特别是,同步this是一个坏主意,除非您打算允许您班级的用户获得锁定.

但是,如果你选择在a上进行同步,则会出现一个特别难看的情况java.lang.String.字符串可以(实际上几乎总是)实习.这意味着在ENTIRE JVM中,每个相同内容的字符串在幕后都是相同的字符串.这意味着如果您同步任何String,另一个(完全不同的)代码部分也会锁定具有相同内容的String,实际上也会锁定您的代码.

我曾经在生产系统中对死锁进行故障排除,并且(非常痛苦地)跟踪两个完全不同的开源软件包的死锁,每个软件包都在一个内容都是String的String实例上同步"LOCK".


关于String实例锁的有用的真实世界轶事+1.

2> Yuval Adam..:

首先,请注意以下代码段是相同的.

public void foo() {
    synchronized (this) {
        // do something thread-safe
    }
}

和:

public synchronized void foo() {
    // do something thread-safe
}

同样的事情.除了代码可读性和样式之外,对它们中的任何一个都没有偏好.

当您同步方法或代码块时,重要的是要知道为什么要做这样的事情,以及您正在锁定什么对象,以及用于何种目的.

另请注意,在某些情况下,您需要客户端同步代码块,其中您要求的监视器(即同步对象)不一定this,如下例所示:

Vector v = getSomeGlobalVector();
synchronized (v) {
    // some thread-safe operation on the vector
}

我建议你对并发编程有更多的了解,一旦你确切知道幕后发生了什么,它将为你提供很多帮助.你应该查看Java中的Concurrent Programming,这是一本关于这个主题的好书.如果您想快速了解主题,请查看Java Concurrency @ Sun


最明显的区别是synchronized(this)块编译为比同步方法更长的字节码.编写synchronized方法时,编译器只在方法上放置一个标志,JVM在看到标志时获取锁.当您使用synchronized(this)块时,编译器会生成类似于try-finally块的字节码,该块获取并释放锁并将其内联到您的方法中.
@jason指向一个关于DCL的文档,因为"它指出编译器或JMM可能会做出意想不到的事情"是过度的,而不是真正的重点.您必须指定为什么它们不相同.大多数人都认为它们是等效的:http://stackoverflow.com/questions/417285
请注意,同步方法通常不是最佳选择,因为我们在方法运行的整个过程中保持锁定.如果它包含耗时但线程安全的部分,以及不那么耗时的线程不安全部分,则同步方法是非常错误的.

3> Bombe..:

我试图避免同步,this因为这将允许来自外部的所有参与该对象的人阻止我的同步.相反,我创建了一个本地同步对象:

public class Foo {
    private final Object syncObject = new Object();
    …
}

现在我可以使用该对象进行同步,而不必担心任何人"窃取"锁定.


谁会试图以某种方式"阻止你的同步",以便同步这个会变得危险,不实用或无法使用?
使堆栈跟踪更具可读性,您可能希望为锁定对象的类提供一个名称,以显示它是哪个锁:`private static class Lock {}; private final Object lock = new Lock();`.
如果您的程序中有错误,请调试.我非常怀疑,如果你已经没有真正了解你的多线程程序中发生的事情的话,避免synchronized(this)会对你有所帮助.
盲目锁定'this'的另一个问题是你可能有几个方法在同一个锁上竞争,逻辑上不需要互斥.
@eljenso - 我concu.锁定"this"可以允许外部调用者"原子化"多个方法调用,这可能是非常宝贵的; 考虑迭代同步集合; 或者PrintWriters使用私有锁的痛苦 - 曾经尝试过不间断地编写堆栈跟踪?

4> Kent Lai..:

只是为了强调Java中还有ReadWriteLocks,可以找到java.util.concurrent.locks.ReadWriteLock.

在我的大部分用法中,我将锁定分为"阅读"和"更新".如果您只使用synchronized关键字,则对同一方法/代码块的所有读取都将"排队".一次只能有一个线程访问该块.

在大多数情况下,如果您只是在阅读,就不必担心并发问题.当你在写作时,你担心并发更新(导致数据丢失),或者在写入(部分更新)期间读取,你必须担心.

因此,在多线程编程期间,读/写锁对我来说更有意义.

推荐阅读
大大炮
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有