简体   繁体   English

Java线程同步方法

[英]Java Thread Synchronized methods

I have the following code 我有以下代码

import java.util.concurrent.*;
public class dsd {

 private static boolean stopRequested;
 private static void requestStop() {
  stopRequested = true;
 }
 private static synchronized boolean stopRequested() {
  return stopRequested;
 }
 public static void main(String[] args)
 throws InterruptedException {
  Thread backgroundThread = new Thread(new Runnable() {
   public void run() {
    int i = 0;
    while (!stopRequested())
     i++;
   }
  });
  backgroundThread.start();
  TimeUnit.SECONDS.sleep(1);
  requestStop();
 }
}

The question is why it works even if requestStop() is not synchronized? 问题是,即使requestStop()不同步,为什么它仍然有效? If I try to do the same thing to the stopRequested() , it doesn't work anymore. 如果我尝试对stopRequested()执行相同的stopRequested() ,那么它将不再起作用。 Why is there no problem with concurrency of the threads on that variable? 为什么该变量上的线程并发没有问题? I know that synchronization makes a variable appear in a consistent state by other threads. 我知道同步使变量被其他线程以一致的状态出现。 But here the variable is not synchronized and it seems that is has no effect. 但是这里的变量没有同步,似乎没有作用。

synchronized is reentrant, the same thread that acquired the lock of synchronized block is guaranteed that it'll keep it on the next try to acquired if it still own the lock, but this doesn't have to do with the fact that the change over stopRequested is made outside a synchronized block and still the code works, your code still may have a race condition under it actual circumstances. synchronized是可重入的,保证了获取同步块锁的同一线程将确保在仍然尝试拥有该锁的情况下,将其保留在下一次尝试中,但这与更改的事实无关在同步块外发出stopRequested ,但代码仍然有效,在实际情况下,您的代码仍可能存在竞争状态。

Let say that at execution N the thread must terminate due on condition meet by stopRequested() and at the same time the requestStop() is called, it's not guaranteed that the thread terminate at N+1 because the variable stopRequested is not protected by exclusive lock in both accessor methods, nor the variable has volatile modifier. 假设在执行N ,线程必须因stopRequested()满足条件而终止,并且同时调用requestStop() ,但不能保证线程在N+1处终止,因为变量stopRequested不受排他保护。锁定两种访问器方法,变量也不具有volatile修饰符。 That means that the sense of correctness you have about the code, is partially wrong, because of race conditions. 这意味着由于竞争条件,您对代码的正确性在某种程度上是错误的。

The Java Lanaguage Specification does not say if or when this program will terminate. Java语言规范没有说明该程序是否或何时终止。

You can only be sure it will terminate after approximately one second if both methods, requestStop() and stopRequested() , are synchronized. 您只能确保如果两个方法requestStop()stopRequested()都同步,它将在大约一秒钟后终止。

If either one is not synchronized, or if neither of them is synchronized, then the program could terminate after one second, or after five seconds, or never. 如果其中一个未同步,或者两个都不同步,则程序可能在一秒钟后或五秒钟后终止,或者永远不会终止。 It could behave differently in different Java Run-time Environments. 在不同的Java运行时环境中,它的行为可能有所不同。 It could behave differently on different hardware. 在不同的硬件上,它的行为可能有所不同。 It could behave differently on different days of the week. 在一周的不同日期,其行为可能会有所不同。

Without both methods being synchronized , its behavior is undefined. 如果没有synchronized这两种方法,则其行为是不确定的。

There is a quote by Dion Almaer referenced in the preface of Java Concurrency in Practice : Java Concurrency in Practice的序言中引用了Dion Almaer的一句话:

Dion Almaer, former editor of TheServerSide, recently blogged (after a painful debugging session that ultimately revealed a threading bug) that most Java programs are so rife with concurrency bugs that they work only "by accident". TheServerSide的前编辑Dion Almaer最近写了一篇博客(经过痛苦的调试,最终发现了线程错误),大多数Java程序都充斥着并发错误,以至于它们只能“偶然”地工作。

This is one of those. 这就是其中之一。 The Java language spec does not make any promise that the updated flag will be visible. Java语言规范不保证已更新标志将可见。 If you don't follow the rules then you're at the mercy of the JVM implementation with respect to whether your thread ever sees the new value of your flag. 如果您不遵循规则,那么就您的线程是否看到标志的新值而言,您将受JVM实现的支配。

Some JVM implementations are more forgiving than others, some are designed to be more aggressive about how they cache things. 一些JVM实现比其他实现更宽容,而某些则旨在更加积极地缓存内容。 If it works for you locally that does not mean it will work in production. 如果它在本地对您有效,那并不意味着它将在生产中起作用。

The synchronized blocks have additional semantics in Java. synchronized块在Java中具有其他语义。 They not only provide exclusive execution of blocks of code, but also emit so called memory barriers that guarantee visibility of the results of all the operations between threads. 它们不仅提供代码块的排他执行,而且发出所谓的内存屏障,以保证线程之间所有操作结果的可见性。

So, when you call a synchronized stopRequested() method, you also make all the changes visible to the current thread. 因此,当您调用synchronized stopRequested()方法时,您还将使所有更改对当前线程可见。 If you remove synchronized from this method, you also remove the barrier and JVM doesn't guarantee you that the flag you set in the main thread is visible in the background thread. 如果从此方法中删除synchronized ,那么还将删除障碍,并且JVM不保证您在主线程中设置的标志在后台线程中可见。 That's why you have problems without synchronized . 这就是为什么您无法synchronized就遇到问题的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM