Java同步块

时间:2010-08-04 06:11:19

标签: java multithreading synchronization

如果我们有方法:

public void doSomething(){
    synchronized(this){
        //some code processing here
    }
    String temp = "init"; //instead of i++
    synchronized(this){
        //some other code processing here
    }
}

此方法是否等同于public synchronized void doSomething()

是否有任何理由假设某些执行中的线程调度程序导致与同步整个函数有效的流程相同?那就是:

  • Thread1 进入第一个同步块。
  • Thread2 阻止。
  • Thread1 继续i++并移至第二个同步块,而 Thread2 仍然被阻止。
  • 因此, Thread1 Thread1 退出两个同步块后进入该方法。

我需要知道的是:

  • 我可以依赖所有执行上下文,这两个线程( Thread1 Thread2 )可以同时在方法中吗?例如,第一个同步块中的 Thread2 和第二个同步块中的 Thread1 以实现并发。
  • 是否会有一些执行流程,其中只有一个线程在一个方法中(一次)有效地序列化整个流程,使其等同于public synchronized void doSomething()

6 个答案:

答案 0 :(得分:10)

某些执行中,它将具有与同步整个函数相同的流程,当然 - 但是为了使其真正等同于使方法同步,它必须具有相同的流程< em>所有执行。

实际上,另一个线程有可能在执行过程中获取锁定(无论是对于此方法还是在同一监视器上的其他代码锁定)。如果方法本身是同步的,那么这种情况就不会发生,因此它们并不等同。

(顺便说一下,锁定this通常被认为是不好的做法;我记不起上次写同步方法了。我把锁定在私人监视器上,所以我知道我的代码是唯一可以锁定它们的代码。)

编辑:回复您的修改:

  

我需要知道的是我是否可以   依靠所有执行上下文   两个线程(例如Thread1和   Thread2)可以在方法中   同时,例如第一个中的thread2   同步块和第二个中的thread1   同步块实现并发

绝对不是!保证不会在同一监视器上同步的同步块中有两个线程。

您有三段代码:第一个同步块,未同步部分和第二个同步部分。

一次可以在非同步部分中执行任意数量的线程。对于任何一个实例(因为您在this上进行同步),只有一个线程可以执行同步块的。如果要实现并发,则必须在不同的监视器上进行同步。

此外,听起来你想要保证调度程序让另一个线程在等待它时抓住锁。我不相信有任何这样的保证 - 执行第一个块的线程可以释放锁定但继续在相同的时间片中并在任何其他线程进入之前重新获取它。在一些可能不会发生的JVM中,但我不知道相信周围有任何保证。

答案 1 :(得分:3)

不,不是。例如,对于上面的代码

线程1进入第一个同步块执行它然后退出然后被切换出来。 线程2进入第一个同步块执行增量,然后在切换之前进入第二个同步块。 线程1现在无法继续,直到线程2退出第二个同步块。

如果整个方法同步,则​​不会发生此模式。

答案 2 :(得分:3)

  

我需要知道的是,我是否可以依赖所有执行上下文,两个线程(例如Thread1和Thread2)可以同时在方法中,例如第一个同步块中的thread2和第二个同步块中的thread1实现并发

没有!情况永远不会如此。只有一个锁与this相关联。通过对两个同步块使用相同的锁,如果Thread1位于第二个synchronized块中,则Thread2不可能位于第一个synchronized块中。

所有其他答案都说明您发布的方法与同步整个方法的方法在技术上是否正确无关。

答案 3 :(得分:2)

鉴于synchronized关键字用于在Java中实现监视器,因此无法保证给定的代码片段同步。

实际上,有问题的线程是否可以完成第一个同步块,然后在执行下一个块之前执行语句以增加i的值。

我假设变量i包含两个线程之间共享的状态,在这种情况下操作不是线程安全的。为了使操作序列成为线程安全的,您必须确保整个序列一次由一个线程执行。在单独的监视器中执行各个操作与在没有监视器的情况下执行操作一样好;整个序列必须由监视器保护。

更多信息,请访问artima.com sample chapter from Inside the Java Virtual Machine

修改

鉴于该问题现在反映了本地String对象的使用,可以将操作序列视为线程安全。每个线程在堆栈上为String对象创建自己的本地引用;由于String对象的不可变属性,一个线程中对象的任何变异都不会影响另一个(为了所有实际目的创建一个新的String对象,当发生变异时,因此状态不是真正在线程之间共享)。 / p>

<强>强调

尝试线程同步时,如果对共享数据的访问是互斥的,则认为操作序列是线程安全的;这样,一个线程将无法读取或写入共享变量,而另一个线程正在执行涉及共享数据的操作。仅使用局部变量,消除了线程之间的任何共享感。

答案 4 :(得分:1)

不,它不等同于synchronized void doSomething(),因为i++不是原子操作。事实上,它可能会像

那样

int temp = i; i = i + 1; result = temp

如果这些操作不是原子的,那么i的值可以在处于错误状态时读取。

答案 5 :(得分:0)

此方法与使其成为同步方法不同。 您可能会看到您解释的行为,但永远不能保证。