每当在SO上出现关于Java同步的问题时,有些人都急于指出应该避免同步(这一点)。相反,他们声称,对私有引用的锁定是首选的。

其中一些原因是:

一些邪恶的代码可能会偷你的锁(这个很流行,也有一个“意外”变体) 同一类中的所有同步方法都使用完全相同的锁,这降低了吞吐量 你(不必要地)暴露了太多信息

包括我在内的其他人认为,synchronized(this)是一个被大量使用的习语(在Java库中也是如此),是安全的,而且很容易理解。它不应该被避免,因为你有一个错误,你不知道你的多线程程序中发生了什么。换句话说:如果它是适用的,那么就使用它。

我感兴趣的是看到一些现实世界的例子(没有foobar的东西),避免锁定在这是可取的,当同步(这)也会做的工作。

因此:您应该总是避免synchronized(this),并将其替换为私有引用上的锁吗?


一些进一步的信息(随着答案的更新):

we are talking about instance synchronization both implicit (synchronized methods) and explicit form of synchronized(this) are considered if you quote Bloch or other authorities on the subject, don't leave out the parts you don't like (e.g. Effective Java, item on Thread Safety: Typically it is the lock on the instance itself, but there are exceptions.) if you need granularity in your locking other than synchronized(this) provides, then synchronized(this) is not applicable so that's not the issue


当前回答

我将分别讨论每一点。

Some evil code may steal your lock (very popular this one, also has an "accidentally" variant) I'm more worried about accidentally. What it amounts to is that this use of this is part of your class' exposed interface, and should be documented. Sometimes the ability of other code to use your lock is desired. This is true of things like Collections.synchronizedMap (see the javadoc). All synchronized methods within the same class use the exact same lock, which reduces throughput This is overly simplistic thinking; just getting rid of synchronized(this) won't solve the problem. Proper synchronization for throughput will take more thought. You are (unnecessarily) exposing too much information This is a variant of #1. Use of synchronized(this) is part of your interface. If you don't want/need this exposed, don't do it.

其他回答

不,你不应该总是这样。但是,当一个特定对象上有多个关注点时,我倾向于避免它,而这些关注点只需要对它们本身是线程安全的。例如,你可能有一个可变数据对象,它有“label”和“parent”字段;它们需要是线程安全的,但是改变其中一个不需要阻止另一个被写入/读取。(在实践中,我将通过声明字段为volatile和/或使用java.util来避免这种情况。concurrent的AtomicFoo包装器)。

一般来说,同步有点笨拙,因为它只是一个大的锁定,而不是仔细考虑如何允许线程相互工作。使用synchronized(this)更加笨拙和反社会,因为它表示“当我持有锁时,没有人可以更改这个类的任何内容”。你需要多久做一次?

I would much rather have more granular locks; even if you do want to stop everything from changing (perhaps you're serialising the object), you can just acquire all of the locks to achieve the same thing, plus it's more explicit that way. When you use synchronized(this), it's not clear exactly why you're synchronizing, or what the side effects might be. If you use synchronized(labelMonitor), or even better labelLock.getWriteLock().lock(), it's clear what you are doing and what the effects of your critical section are limited to.

我只想提到一种可能的解决方案,用于在没有依赖关系的原子代码部分中惟一的私有引用。您可以使用带锁的静态Hashmap和名为atomic()的简单静态方法,该方法使用堆栈信息(完整的类名和行号)自动创建所需的引用。然后,您可以在同步语句中使用此方法,而无需写入新的锁对象。

// Synchronization objects (locks)
private static HashMap<String, Object> locks = new HashMap<String, Object>();
// Simple method
private static Object atomic() {
    StackTraceElement [] stack = Thread.currentThread().getStackTrace(); // get execution point 
    StackTraceElement exepoint = stack[2];
    // creates unique key from class name and line number using execution point
    String key = String.format("%s#%d", exepoint.getClassName(), exepoint.getLineNumber()); 
    Object lock = locks.get(key); // use old or create new lock
    if (lock == null) {
        lock = new Object();
        locks.put(key, lock);
    }
    return lock; // return reference to lock
}
// Synchronized code
void dosomething1() {
    // start commands
    synchronized (atomic()) {
        // atomic commands 1
        ...
    }
    // other command
}
// Synchronized code
void dosomething2() {
    // start commands
    synchronized (atomic()) {
        // atomic commands 2
        ...
    }
    // other command
}

这要视情况而定。 如果只有一个或多个共享实体。

在这里查看完整的工作示例

简单介绍一下。

线程和可共享实体 多个线程可以访问同一个实体,例如多个connectionThreads共享一个messageQueue。由于线程并发运行,可能会有一个数据被另一个覆盖的机会,这可能是一个混乱的情况。 因此,我们需要某种方法来确保可共享实体一次只能被一个线程访问。(并发)。

同步块 Synchronized()块是一种确保可共享实体并发访问的方法。 首先,打个小比方 假设有两个人P1, P2(线程)一个盥洗室(可共享实体),有一扇门(锁)。 现在我们想让一个人一次使用脸盆。 一种方法是在P1锁门的时候P2等待P1完成他的工作 P1打开门 那么只有p1可以使用脸盆。

语法。

synchronized(this)
{
  SHARED_ENTITY.....
}

"this" provided the intrinsic lock associated with the class (Java developer designed Object class in such a way that each object can work as monitor). Above approach works fine when there are only one shared entity and multiple threads (1: N). N shareable entities-M threads Now think of a situation when there is two washbasin inside a washroom and only one door. If we are using the previous approach, only p1 can use one washbasin at a time while p2 will wait outside. It is wastage of resource as no one is using B2 (washbasin). A wiser approach would be to create a smaller room inside washroom and provide them one door per washbasin. In this way, P1 can access B1 and P2 can access B2 and vice-versa.

washbasin1;  
washbasin2;

Object lock1=new Object();
Object lock2=new Object();

  synchronized(lock1)
  {
    washbasin1;
  }

  synchronized(lock2)
  {
    washbasin2;
  }


在这里查看更多关于Threads---->的信息

这取决于你想做的任务,但我不会用它。此外,检查您想要完成的线程保存是否不能首先通过同步(此)来完成?API中也有一些不错的锁,可能会帮助到你:)

我认为第一点(其他人使用您的锁)和第二点(所有方法不必要地使用相同的锁)可能发生在任何相当大的应用程序中。特别是当开发人员之间没有良好的沟通时。

这不是一成不变的,这主要是一个良好的实践和防止错误的问题。