Java 同步块

发布于 2024-09-12 23:10:25 字数 912 浏览 7 评论 0原文

如果我们有一个方法:

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 仍处于阻塞状态。
  • 因此,Thread2Thread1 退出两个同步块后进入该方法。

我需要知道的是:

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

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()?

Is there any reason not to assume that the thread scheduler in some executions would not result in effectively the same flow as synchronizing the whole function? That is:

  • Thread1 enters the first synchronized block.
  • Thread2 blocks.
  • Thread1 continues with i++ and moves to the second synchronized block while Thread2 remains blocked.
  • As a result, Thread2 enters the method after Thread1 has exited both synchronized blocks.

All I need to know is:

  • Can I count on all execution contexts that both threads (Thread1 and Thread2) can be in the method at the same time? For example, Thread2 in the first sync block and Thread1 in 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()?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

月亮坠入山谷 2024-09-19 23:10:25

当然,在某些执行中,它会具有与同步整个函数相同的流程 - 但要真正等效于使方法同步,它必须对所有执行具有相同的流程 处决。

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

(顺便说一句,无论如何,锁定 this 通常被认为是不好的做法;我不记得上次编写同步方法是什么时候了。我改为锁定私有监视器,以便我知道我的代码是唯一可能锁定它们的代码。)

编辑:响应您的编辑:

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

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

您有三部分代码:第一个同步块、非同步部分和第二个同步部分。

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

此外,听起来您希望保证调度程序让另一个线程在等待时获取锁。我不相信有任何这样的保证——执行第一个块的线程可以释放锁,但在相同的时间片中继续,并在任何其他线程进入之前重新获取它。在某些 JVM 中,这可能不会发生,但我不这样做不相信有任何保证。

In some executions 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 all executions.

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 this is 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.)

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

Absolutely not! It's guaranteed that you won't have 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 either of the synchronized blocks. If you want to achieve concurrency, you'd have to synchronize on different monitors.

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.

深爱不及久伴 2024-09-19 23:10:25

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

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

如果整个方法都是同步的,这种模式就不会发生。

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.

This pattern cannot happen if the entire method is sync'd.

梦言归人 2024-09-19 23:10:25

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

不!但事实并非如此。只有一把锁与 this 关联。由于对两个同步块使用相同的锁,如果线程 1 位于第二个同步块中,则线程 2 不可能位于第一个同步块中。

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

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

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 synchronized block if Thread1 is in the second synchronized block.

All other answers stating that the method you posted is not the same as synchronizing the whole method are technically correct.

明天过后 2024-09-19 23:10:25

鉴于Java中使用synchronized关键字来实现监视器,因此不能保证给定的代码片段是同步的。

实际上,有可能两个线程都完成第一个同步块,然后在执行下一个块之前执行语句来增加 i 的值。

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

更多信息请访问 artima.com 中的Inside the Java Virtual Machine

编辑

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

强调

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

Given that the synchronized keyword is used to implement monitors in Java, the given piece of code cannot be guaranteed to be 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'm assuming that the variable i contains 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.

More info at artima.com in the sample chapter from Inside the Java Virtual Machine.

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).

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.

孤星 2024-09-19 23:10:25

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

int temp = i; 的操作。我=我+1; result = temp

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

No, it's not equivalent to synchronized void doSomething() because i++ is not an atomic operation. In fact, it probably does something like

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

If those operations are not made atomic, then the value of i could be read while it is in a bad state.

南七夏 2024-09-19 23:10:25

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

This method is not same as making it a synchronized method.
The behavior you explained may be seen but can never be guranteed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文