为什么在Java中同步单个语句?

为什么在Java中同步单个语句?,java,android,synchronization,android-mediaplayer,Java,Android,Synchronization,Android Mediaplayer,我是一个模拟人,正在学习如何在android上编码,所以如果这个问题听起来很愚蠢,请容忍我 我理解同步的要点。如果我有两个线程可以访问和修改的数据,则可能会导致两个线程中的数据变量值不一致 使方法同步并锁定它们直到一个线程执行它(执行任何条件检查)为止是有意义的,但是为什么它与单个语句有关呢?对于多个语句来说这很重要,因为在两个或多个语句之间有可能出现线程一脱离可运行状态的情况,但我不明白单个语句的意义何在 这里有一个例子 如果我有一个可以从游戏线程调用的侦听器,并且它修改了一个数据变量,为什么

我是一个模拟人,正在学习如何在android上编码,所以如果这个问题听起来很愚蠢,请容忍我

我理解同步的要点。如果我有两个线程可以访问和修改的数据,则可能会导致两个线程中的数据变量值不一致

使方法同步并锁定它们直到一个线程执行它(执行任何条件检查)为止是有意义的,但是为什么它与单个语句有关呢?对于多个语句来说这很重要,因为在两个或多个语句之间有可能出现线程一脱离可运行状态的情况,但我不明白单个语句的意义何在

这里有一个例子

如果我有一个可以从游戏线程调用的侦听器,并且它修改了一个数据变量,为什么我要这样做

    public void onCompletionListener(MediaPlayer player){
    synchronized (this){
        isPrepared = false;
       }
    }
我在音乐课上还有另一种方法叫停止

   public void stop(){
   mediaPlayer.stop()
    synchronized(this){
    isPrepared = false;
       }
    }
我为什么要费心这么做?这样做是为了两个线程之间的值的一致性吗?如果是这样,我可以使用类似volatile的东西吗?这样会更好吗

我这样问是因为我听说同步很昂贵。有更好的选择吗

提前谢谢你们回答我的问题。我很感激。 编辑:我读了这个


我想我明白了。。如果有人能详细说明,那就太棒了。关于volatile是否是更好的选择,我最初的问题的第二部分也没有得到回答:)

在布尔值上使用volatile在您的情况下也可以不进行同步。
基本布尔值表示为4字节值,并将写入一条(汇编)语句中


这不保证适用于8字节值(例如长/双字节),其中一个线程可以写入较低的4字节,而另一个线程可以写入较高的4字节。

在您的情况下,使用volatile on boolean也可以在不同步的情况下工作。
基本布尔值表示为4字节值,并将写入一条(汇编)语句中


对于8字节值(例如long/double),一个线程可以写入较低的4个字节,而另一个线程可以写入较高的4个字节,这并不能保证工作正常。

之所以这样做,是因为同步还对线程之间的内存可见性提出了要求

如果该写操作不同步或不稳定,那么对于其他线程何时可以看到它就没有任何硬性要求。另一个线程的堆栈中可能有一个名为true的
isPrepared
副本,如果没有同步或易失性引用,它可以永远运行,而不需要返回主内存并检查其他线程是否更改了
isPrepared


volatile关键字将满足确保其他线程看到更新的直接要求。如果看不到整个类/系统,就无法确定它是否是可接受的替代品。可能还有其他同步方法,在其中一个处于执行中时更改isPrepared的状态是非法的。显然,删除同步而使用易失性引用将是一个错误。

之所以这样做,是因为同步还提出了线程之间内存可见性的要求

如果该写操作不同步或不稳定,那么对于其他线程何时可以看到它就没有任何硬性要求。另一个线程的堆栈中可能有一个名为true的
isPrepared
副本,如果没有同步或易失性引用,它可以永远运行,而不需要返回主内存并检查其他线程是否更改了
isPrepared


volatile关键字将满足确保其他线程看到更新的直接要求。如果看不到整个类/系统,就无法确定它是否是可接受的替代品。可能还有其他同步方法,在其中一个处于执行中时更改isPrepared的状态是非法的。显然,删除同步而使用易失性引用将是一个错误。

作为对前面答案的补充,我想补充的是,在某些情况下,可以将单行源代码转换为多行机器可执行代码,例如

柜台++

尽管它看起来像一个操作,但表达式计数器++实际上是三个 单独操作:

1) 读取计数器的值

2) 将1添加到此值

3) 将更新后的值存储在计数器中


因此,这种语句也应该在多线程上下文中同步。

作为对前面答案的补充,我想补充一点,在某些情况下,您的单行源代码可以转换为多行机器可执行代码,例如

柜台++

尽管它看起来像一个操作,但表达式计数器++实际上是三个 单独操作:

1) 读取计数器的值

2) 将1添加到此值

3) 将更新后的值存储在计数器中


因此,此类语句也应在多线程上下文中同步。

除非您正在编写高性能、高多线程的应用程序,其中使用了来自多线程的复杂数据结构,否则最好忘记“同步是昂贵的”。参考的“单语句同步”thread也回答了您问题中不稳定的部分。“Java 5内存模型”链接:除非您正在编写高性能、高度多线程的应用程序,其中使用多个线程的复杂数据结构,否则最好忘记“同步是昂贵的”。引用的“单语句同步”线程也回答了问题中的易失性部分。“Java5内存模型”链接:添加易失性不仅仅是确保线程之间的值不一致。我