Java线程同步方法

问题描述 投票:1回答:4

我有以下代码

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();
 }
}

问题是,即使requestStop()不同步,它仍然有效吗?如果我尝试对stopRequested()做同样的事情,它就不再起作用了。为什么该变量上的线程并发没有问题?我知道同步使变量出现在其他线程的一致状态中。但是这里变量不同步,似乎没有效果。

java multithreading synchronized
4个回答
2
投票

synchronized是可重入的,获得同步块锁的同一个线程保证,如果它仍然拥有锁,它将保留下一次尝试获取它,但这与更改的事实无关stopRequested是在同步块之外进行的,代码仍然有效,你的代码在实际情况下仍可能有竞争条件。

假设在执行N时,线程必须在stopRequested()条件满足时终止,同时调用requestStop(),不能保证线程终止于N+1,因为变量stopRequested在两种存取方法中都不受独占锁保护,变量也没有volatile修饰符。这意味着由于竞争条件,你对代码的正确感是部分错误的。


1
投票

Java语言规范没有说明此程序是否或何时终止。

如果两种方法requestStop()stopRequested()同步,你只能确定它会在大约一秒后终止。

如果其中任何一个未同步,或者它们都未同步,则程序可能在一秒钟后或五秒钟后终止,或者从不终止。它可能在不同的Java运行时环境中表现不同。它可能在不同的硬件上表现不同。它可能在一周的不同日期表现不同。

如果两种方法都不是synchronized,那么它的行为是不确定的。


1
投票

synchronized块在Java中具有额外的语义。它们不仅提供代码块的独占执行,而且还发出所谓的内存屏障,以保证线程之间所有操作的结果的可见性。

因此,当您调用synchronized stopRequested()方法时,您还可以对当前线程显示所有更改。如果从此方法中删除synchronized,则还会删除屏障,并且JVM不保证您在主线程中设置的标志在后台线程中可见。这就是没有synchronized你有问题的原因。


1
投票

Dion Almaer引用了Java Concurrency in Practice的前言:

TheServerSide的前编辑Dion Almaer最近发表了博客(经过一次痛苦的调试会议,最终揭示了一个线程错误),大多数Java程序都充斥着并发错误,他们只能“偶然”工作。

这是其中之一。 Java语言规范没有做出更新标志可见的承诺。如果你不遵守这些规则,那么就你的线程是否看到你的标志的新值而言,你将受JVM实现的支配。

有些JVM实现比其他实现更宽容,有些实现了更积极的缓存方式。如果它在本地适用于您并不意味着它将在生产中起作用。

© www.soinside.com 2019 - 2024. All rights reserved.