0

我有一个简单的问题,但很难找到答案。

问题是同步方法是否等于 synchronized(this) - 意味着做相同的锁定。

我想编写减少线程锁定的线程安全代码(不想使用总是同步的方法,但有时只使用部分同步关键部分)。

您能否解释一下这段代码是否相等以及为什么简而言之(简化示例以显示原子问题)?

例子

这个混合锁定代码是否等于下面的蛮力代码:

public class SynchroMixed {
    int counter = 0;

    synchronized void writer() {
        // some not locked code
        int newCounter = counter + 1;

        // critical section
        synchronized(this) {
            counter = newCounter;
        }
    }

    synchronized int reader() {
        return counter;
    }
}

蛮力代码(每个方法都被锁定,包括非关键部分:

public class SynchroSame {
    int counter = 0;

    synchronized void writer() {
        int newCounter = counter + 1;

        counter = newCounter;
    }

    synchronized int reader() {
        return counter;
    }
}

或者我应该编写这段代码(这肯定是有效的,但更多的是微编码且不清楚)。

public class SynchroMicro {
    int counter = 0;

    void writer() {
        // some not locked code
        int newCounter = counter + 1;

        // critical section
        synchronized(this) {
            counter = newCounter;
        }
    }

    int reader() {
        synchronized (this) {
            return counter;
        }
    }
}
4

4 回答 4

3

synchronized method and synchronized(this) means absolutely the same thing, and uses the same mutex behind. It's more question of taste what notation to prefer.

Personally I prefer synchronized(this), because it explicitly specifies the scope of the mutex lock which could be smaller than the whole method

于 2013-03-13T11:18:34.853 回答
2

synchronized(this)在方法中肯定没有意义,synchronized因为进入方法已经是隐含的synchronized(this)

这只是您的语法错误,因为您显然打算缩小临界区的范围,但缩小的范围会在您的代码中引入数据竞争:您必须在同一块中读取写入共享变量。synchronized

此外,即使一个方法读取共享变量,它仍然必须在一个synchronized块中进行;否则它可能永远不会观察到其他线程的任何写入。这是 Java 内存模型的基本语义。

现在,如果您所展示的内容确实代表了您的全部问题,那么您甚至不应该使用synchronized,而应该使用简单AtomicInteger的 ,它将具有最佳的并发性能。

于 2013-03-13T11:20:32.340 回答
2

这三个例子都是等价的。在方法上使用synchronized与将整个主体包裹在synchronized(this) {}.

然后,通过使用synchronized(this) {}for 某些语句,线程只是重新获取它已经拥有的锁:在这里没有意义。

于 2013-03-13T11:21:38.970 回答
2

从功能的角度来看,同步方法和块是绝对相似的。它们都执行相同的任务,即避免同时访问特定方法或方法中的代码块。

当您有一个长方法并且只需要同步其中的一部分时,synchronized() 块会更加灵活和方便。您不需要锁定对整个方法的访问,因为我们知道同步有一些与之相关的性能问题。因此,始终建议只同步部分代码而不是整个方法(如果不需要)。

于 2013-03-13T12:59:50.953 回答