Java线程同步块行为 - 同步与同步()? [复制]

Posted

技术标签:

【中文标题】Java线程同步块行为 - 同步与同步()? [复制]【英文标题】:Java threading synchronized block behavior - synchronized vs synchronized()? [duplicate] 【发布时间】:2013-03-01 07:04:42 【问题描述】:

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

问题是同步方法是否等于 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;
        
    

【问题讨论】:

在您的第一个示例中,“一些未锁定的代码”语句仍在 synchronized 方法中。这是您的意图还是错字? 一模一样,看看这个[链接][1][1]:***.com/questions/574240/… 【参考方案1】:

synchronized 方法和synchronized(this) 表示完全一样的东西,并且在后面使用相同的互斥锁。更多的是品味问题,更喜欢哪种符号。

我个人更喜欢synchronized(this),因为它明确指定了互斥锁的范围,可能小于整个方法

【讨论】:

另外:synchronized(this)synchronized 方法中绝对没有效果。 @JoachimSauer:是的,因为 Java 互斥锁是可重入的,所以没有效果 @JoachimSauer 我在代码方法不同步时犯了错误 - 现在从代码中删除它 - 正如你所说,自从第一次覆盖第二次以来,没有意义双重同步。 我更喜欢简短的符号 synchronized' and synchronized(this)` 如果它等于并且比 Java 更多 Python 因为更灵活 - 你可以编写类型检查代码,但你可以避免它并去除 50% 的装饰和可以使用多重继承 - 你可以从许多类中创建类(Java 强制代码克隆而不是减少)。【参考方案2】:

synchronized 方法中的synchronized(this) 绝对没有意义,因为进入该方法已经隐含synchronized(this)

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

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

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

【讨论】:

我只使用 int 和示例 - 好答案!正如您发现的那样,由于“同步”而不是“同步(此)”没有意义,因此存在错误 - 我忘记了方法中的删除修饰符。【参考方案3】:

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

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

【讨论】:

很高兴听到这是相等的代码,感谢您的帮助!【参考方案4】:

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

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

【讨论】:

以上是关于Java线程同步块行为 - 同步与同步()? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

java加锁与同步方法

java加锁与同步方法

java多线程-同步块

阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第3节 线程同步机制_4_解决线程安全问题_同步代码块

java 同步代码块与同步方法

java的两种同步方式, Synchronized与ReentrantLock的区别