【问题标题】:Replacing volatile with synchronized block is not working用同步块替换 volatile 不起作用
【发布时间】:2015-04-01 07:50:50
【问题描述】:

我正在阅读this 教程。我了解 volatile 关键字的用法。但是,当我尝试在不使用 volatile 关键字的情况下通过在同步块中对关注变量进行操作来实现相同的结果时,它不起作用。它抛出 IllegalMonitorStateException。这是我尝试的修改后的代码。

public class VolatileTest {
private static Integer MY_INT = 0;

public static void main(String[] args) {
    new ChangeListener().start();
    new ChangeMaker().start();
}

static class ChangeListener extends Thread {
    @Override
    public void run() {
         synchronized(MY_INT){
        int local_value = MY_INT;
        while ( local_value < 5){
            if( local_value!= MY_INT){
                System.out.format("Got Change for MY_INT : {0}", MY_INT);
                 local_value= MY_INT; 
                  try {
                MY_INT.wait();
            } catch (Exception e) { e.printStackTrace(); }}
            }
        }
    }
}

static class ChangeMaker extends Thread{
    @Override
    public void run() {
         synchronized(MY_INT){
        int local_value = MY_INT;
        while (MY_INT <5){
            System.out.format("Incrementing MY_INT to {0}", local_value+1);
            MY_INT = ++local_value;
            try {
                MY_INT.notify();
            } catch (Exception e) { e.printStackTrace(); }
        }
    }
}}}

我想知道的是,在这种情况下,可以用同步块替换 volatile,如果是,那么该怎么做? 谢谢。

【问题讨论】:

  • 请提供异常堆栈跟踪。

标签: java multithreading thread-safety


【解决方案1】:

问题出在这里:

 MY_INT = ++local_value;

MY_INT 是一个Integer 变量,当您为其分配新值时,您在此处锁定的对象:

 synchronized(MY_INT){

将与您在此处通知的对象不同:

  MY_INT.notify();

...这将导致异常。


解决办法是把锁对象设为static final。显然这意味着你不能分配给它......但这就是重点!

【讨论】:

  • 很好的答案,除了整数对象的不变性不是问题。任何时候你有一个变量Foo foo;,并分配给它foo = ...;,都会更新对象引用。 Foo 类是否不可变并不重要。
  • 是的,但是菜鸟很容易误解您所说的“整数对象是不可变的。当您分配给整数变量时......”。这是两个独立的子句,但是当你把它们放在同一个段落中时,不熟悉该语言的人可能会记得它,就好像你说过,因为整数对象是不可变的......
猜你喜欢
  • 2023-03-30
  • 2019-02-19
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-15
  • 1970-01-01
  • 2011-08-22
相关资源
最近更新 更多