Java 同步块
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3403030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java synchronized blocks
提问by Cratylus
If we have a method:
如果我们有一个方法:
public void doSomething(){
synchronized(this){
//some code processing here
}
String temp = "init"; //instead of i++
synchronized(this){
//some other code processing here
}
}
Is this method equivalent to public synchronized void doSomething()?
这个方法等价于public synchronized void doSomething()?
Is there any reason notto assume that the thread scheduler in some executions would notresult in effectively the same flow as synchronizing the whole function? That is:
是否有任何理由不假设某些执行中的线程调度程序不会有效地产生与同步整个函数相同的流程?那是:
- Thread1enters the first synchronized block.
- Thread2blocks.
- Thread1continues with
i++and moves to the second synchronized block while Thread2remains blocked. - As a result, Thread2enters the method after Thread1has exited both synchronized blocks.
- Thread1进入第一个同步块。
- 线程 2块。
- Thread1继续
i++并移动到第二个同步块,而Thread2保持阻塞。 - 其结果是,线程2进入后的方法线程1已经退出都同步块。
All I need to know is:
我需要知道的是:
- Can I count on all execution contexts that both threads (Thread1and Thread2) can be in the method at the same time? For example, Thread2in the first sync block and Thread1in the second sync block to achieve concurrency.
- Will there be some execution flows where only one thread will be in the method (at a time) effectively serializing the whole flow, making it equivalent to
public synchronized void doSomething()?
- 我可以对所有执行上下文计算这两个线程(线程1和线程2)可以在同一时间在该方法?例如,线程2在第一同步块和线程1中的第二同步块,以实现并发。
- 是否会有一些执行流程,其中方法中只有一个线程(一次)有效地序列化整个流程,使其等效于
public synchronized void doSomething()?
回答by Jon Skeet
In someexecutions it would have the same flow as synchronizing the whole functions, sure - but for it to be truly equivalent to making the method synchronized, it would have to have the same flow for allexecutions.
在某些执行中,它会与同步整个函数具有相同的流程,当然 - 但为了真正等同于使方法同步,它必须对所有执行具有相同的流程。
As it is, there's a possibility that another thread will grab the lock (whether for this method or some other code locking on the same monitor) half way through execution. That couldn't happen if the method itself were synchronized, therefore they're not equivalent.
事实上,另一个线程可能会在执行到一半时获取锁(无论是针对此方法还是同一监视器上的其他代码锁定)。如果方法本身是同步的,则不会发生这种情况,因此它们不是等效的。
(As an aside, locking on thisis generally considered to be bad practice anyway; I can't remember the last time I wrote a synchronized method. I lock on privately held monitors instead, so that I know my code is the only code which can possibly lock on them.)
(顺便this说一句,无论如何,锁定通常被认为是不好的做法;我不记得我上次编写同步方法是什么时候。我改为锁定私人持有的监视器,所以我知道我的代码是唯一可以可能锁定他们。)
EDIT: To respond to your edit:
编辑:要回应您的编辑:
All I need to know is whether I can count on all execution contexts that both threads (e.g. Thread1 and Thread2) can be in the method at the same time, e.g thread2 in the first sync block and thread1 in the second sync block to achieve concurrency
我需要知道的是我是否可以依靠两个线程(例如Thread1和Thread2)可以同时在方法中的所有执行上下文,例如第一个同步块中的thread2和第二个同步块中的thread1来实现并发
Absolutely not! It's guaranteed that you won'thave two threads both in a synchronized block synchronized on the same monitor.
绝对不!保证在同一个监视器上同步的同步块中不会有两个线程。
You have three sections of code: the first synchronized block, the unsynchronized part, and the second synchronized part.
您有三部分代码:第一个同步块、未同步部分和第二个同步部分。
Any number of threads can be executing in the unsynchronized part at a time. For any one instance (because you're synchronizing on this) only one thread can be executing eitherof the synchronized blocks. If you want to achieve concurrency, you'd have to synchronize on different monitors.
一次可以在未同步部分执行任意数量的线程。对于任何一个实例(因为您正在同步this),只有一个线程可以执行任一同步块。如果要实现并发,则必须在不同的监视器上进行同步。
Furthermore, it sounds like you want guarantees of the scheduler letting another thread grab the lock if it was waiting for it. I don't believe there's any such guarantee - a thread executing the first block could release the lock but continue in the same timeslice and re-acquire it before any other threads got in. In some JVMs that may not happen, but I don't believe there's any guarantee around it.
此外,听起来您想要保证调度程序让另一个线程在等待它时获取锁。我不相信有任何这样的保证 - 执行第一个块的线程可以释放锁,但会在同一时间片中继续并在任何其他线程进入之前重新获取它。在某些 JVM 中可能不会发生,但我没有不相信有任何保证。
回答by Toby
No it's not. For example for the code above
不,这不对。例如对于上面的代码
Thread one enters the first sync'd block executes it and exits then is switched out. Thread two enters the first sync'd block executes it increments i then enters the second sync'd block before being switched out. Thread one now cannot continue until Thread two exits the second sync'd block.
线程一进入第一个同步块执行它并退出然后被切换出去。线程二进入第一个同步块执行它递增 i 然后在被切换之前进入第二个同步块。线程 1 现在无法继续,直到线程 2 退出第二个同步块。
This pattern cannot happen if the entire method is sync'd.
如果整个方法被同步,这种模式就不会发生。
回答by Tim Bender
All I need to know is whether I can count on all execution contexts that both threads (e.g. Thread1 and Thread2) can be in the method at the same time, e.g thread2 in the first sync block and thread1 in the second sync block to achieve concurrency
我需要知道的是我是否可以依靠两个线程(例如Thread1和Thread2)可以同时在方法中的所有执行上下文,例如第一个同步块中的thread2和第二个同步块中的thread1来实现并发
No! This is never the case. There is only one lock associated with this. By virtue of using the same lock for both synchronized blocks, it is impossible for Thread2 to be in the first synchronizedblock if Thread1 is in the second synchronizedblock.
不!情况从来都不是这样。只有一个锁与this. 由于对两个同步块使用相同的锁,如果 Thread1synchronized在第二个synchronized块中,则 Thread2 不可能在第一个块中。
All other answers stating that the method you posted is not the same as synchronizing the whole method are technically correct.
说明您发布的方法与同步整个方法不同的所有其他答案在技术上都是正确的。
回答by Vineet Reynolds
Given that the synchronized keyword is used to implement monitors in Java, the given piece of code cannot be guaranteed to be synchronized.
鉴于在 Java 中使用了 synchronized 关键字来实现监视器,因此不能保证给定的代码段是同步的。
In reality, is it possible for both the threads in question to complete the first synchronized block, and then execute the statement to increment the value of i, before executing the next block.
实际上,是否有可能两个线程都完成第一个同步块,然后执行语句以增加 的值i,然后再执行下一个块。
I'm assuming that the variable icontains state that is shared between the two threads, in which case the operation is not thread-safe. In order to make the sequence of operations thread-safe you must ensure that the entire sequence is executed by one thread at a time. Executing the individual operations in separate monitors is as good as executing the operations without a monitor; the entire sequence must be guarded by the monitor.
我假设变量i包含在两个线程之间共享的状态,在这种情况下,操作不是线程安全的。为了使操作序列线程安全,您必须确保整个序列一次由一个线程执行。在单独的监视器中执行单个操作与在没有监视器的情况下执行操作一样好;整个序列必须由监视器看守。
More info at artima.com in the sample chapter from Inside the Java Virtual Machine.
更多信息请访问 artima.com 中Java 虚拟机内部的示例章节。
EDIT:
编辑:
Given the fact that the question now reflects the use of a local String object, the sequence of operations can be considered as thread safe. Each thread creates its own local reference on the stack to the String object; any mutation of the object in one thread, will not affect the other due to the immutable property of String objects (a new String object is created for all practical purposes, when mutation occurs, and therefore state is not truly shared across threads).
鉴于问题现在反映了本地 String 对象的使用,操作序列可以被认为是线程安全的。每个线程在堆栈上创建自己对 String 对象的本地引用;由于 String 对象的不可变属性,一个线程中对象的任何突变都不会影响另一个线程(当发生突变时,会为所有实际目的创建一个新的 String 对象,因此状态不会真正跨线程共享)。
Emphasis:
重点:
When attempting synchronization of threads, consider the sequence of operations to be thread-safe if access to shared data is made mutually exclusive; that way one thread will not be able to read or write to the shared variables, while the other is performing an operation involving the shared data. Using local variables only, removes any sense of sharing among threads.
当尝试同步线程时,如果对共享数据的访问是互斥的,则考虑操作序列是线程安全的;这样一个线程将无法读取或写入共享变量,而另一个线程正在执行涉及共享数据的操作。仅使用局部变量,消除了线程间共享的任何意义。
回答by Nate W.
No, it's not equivalent to synchronized void doSomething()because i++is not an atomic operation. In fact, it probably does something like
不,它不等同于synchronized void doSomething()因为i++不是原子操作。事实上,它可能会做类似的事情
int temp = i; i = i + 1; result = temp
int temp = i; i = i + 1; result = temp
If those operations are not made atomic, then the value of icould be read while it is in a bad state.
如果这些操作不是原子的,则i可以在处于错误状态时读取的值。
回答by Gopi
This method is not same as making it a synchronized method. The behavior you explained may be seen but can never be guranteed.
此方法与使其成为同步方法不同。您解释的行为可能会被看到,但永远无法保证。

