java - 多线程处理 - 在Java关键部分中,我应该同步什么?

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


private void doSomething() {


 // thread-safe code


 synchronized(this) {


 // thread-unsafe code


 }


 // thread-safe code


}



几乎所有块都在this上同步,但是,这是否有特殊的原因? 还有其他可能吗,有什么最佳实践,可以同步什么对象?(例如Object的私有实例)?

时间:

首先,请注意,下面的代码片段是相同的。


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并发@Sun

我试图避免在this上同步,因为这将允许外部的每个人都有引用该对象的引用,相反,我创建了一个本地同步对象:


public class Foo {


 private final Object syncObject = new Object();


 …


}



现在我可以使用这个对象进行同步,而不用担心任何人"窃取"锁。

你需要在一个可以用作互斥体的对象上进行同步,如果当前实例(此引用)适合(不是单一的,例如),你可以使用它,因为在Java中任何对象都可以充当互斥体。

在其他情况下,如果这些类的实例可能都需要访问相同的资源,则可能需要共享一个互斥。

这取决于你正在使用的环境和你正在构建的系统的类型,在我看到的大多数Java EE应用程序中,实际上实际上并不需要同步。

Java中的同步通常涉及同一个实例上的同步操作,在this上同步是非常惯用的,因为this是一个共享引用,可以在类的不同实例方法(或部分)之间自动。

通过声明和初始化私有字段,使用另一个专门用于锁定的引用,Object lock = new Object() 例如,是我从未需要或使用的东西。我认为只有当你需要在一个对象内的两个或多个非同步资源上进行外部同步时它才有用,尽管我总是试图将这种情况重构为一个更简单的形式。

无论如何,隐式(同步方法)或显式synchronized(this)被大量使用,也在Java库中,这是一个好习惯,如果适用的话,应该永远是你的首选。

几乎所有块都是同步的,但是,是否有特殊的原因? 还有其他可能?

此声明同步整个方法。


private synchronized void doSomething() {



此声明同步了代码块的一部分而不是整个方法。


private void doSomething() {


 // thread-safe code


 synchronized(this) {


 // thread-unsafe code


 }


 // thread-safe code


}



来自oracle文档页面

使这些方法同步有两种效果:

首先,同一对象上同步方法的两个调用不能相互交织,当一个线程为对象执行同步方法时,所有调用同一对象的同步方法的线程直到第一个线程。

是否有其他可能性是否有什么最佳实践可以同步到? (例如对象的私有实例)?

同步有许多可能性和替代方案,你可以使用高级并发 (JDK 1.5发布后可用)来保证代码的线程安全


Lock objects


Executors


Concurrent collections


Atomic variables


ThreadLocalRandom



有关更多详细信息,请参阅以下问题:

同步与锁定

在Java中避免synchronized(this)

最佳做法是单独创建一个对象以提供锁:


private final Object lock = new Object();



private void doSomething() {


 // thread-safe code


 synchronized(lock) {


 // thread-unsafe code


 }


 // thread-safe code


}



这样做是安全的,任何调用代码都不会通过无意的synchronized(yourObject)行来死锁你的方法。

)

我猜使用this的流行程度来自早期的Sun javadoc : https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

...