【问题标题】:Java: Volatile variable not updating (get and set methods not working)Java:可变变量未更新(获取和设置方法不起作用)
【发布时间】:2017-07-09 08:14:04
【问题描述】:

我有一个 Runnable "NanoClock" 类,它在其 run() 方法中不断更新私有 volatile double 值。

这个类还有一个getTime() 方法,它返回双精度值。另一个类(“Master”)正在构造NanoClock 类并创建一个线程,同时调用start() 方法。

执行此操作后,它会多次调用getTime() 方法(有延迟),但值没有更新。我做错了什么?

NanoClock.java:

public class NanoClock implements Runnable {
    private volatile boolean running;
    private volatile double time;
    public NanoClock() {
        time = System.currentTimeMillis();
    }
    @Override
    public void run() {
        running = true;
        while(running) {
            try {
                if(System.currentTimeMillis() > time) {
                    time = System.currentTimeMillis();
                }
              //This returns the updated value continuously when commented out
              //System.out.println("Time: " + String.format("%.6f", unix_time));
                Thread.sleep(2000);
            } catch(Exception exc) {
                exc.printStackTrace();
                System.exit(1);
            }
        }
    }
    public double getTime() {
        return time;
    }
    public void end() {
        running = false;
    }
}

Master.java:

public class Master {
    public static void main(String[] args) {
        try {
            NanoClock nClock = new NanoClock();
            Thread clockThread = new Thread(new NanoClock());
            clockThread.setPriority(10);
            clockThread.start();
            //MY_ISSUE: This returns the same value every time
            for(int a = 0; a < 10; a++) {
                System.out.println("Time: " + nClock.getTime());
            }
            //MY_ISSUE: This cannot stop the while loop - I tested it with 
            //the println in the NanoClock class.
            nClock.end();
            System.out.println("Done!");
        catch(Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}

【问题讨论】:

  • 你总是在 run 方法中将 running 设置为 true,所以你的 while 循环永远不会停止......
  • 你认为new NanoClock() 会做什么?
  • @home 但是 run 方法只被调用一次,对吧?所以它应该将running变为true,然后停留在while循环中,直到我将running的值更改为false,这导致完成方法并结束线程......还是run方法本身被连续调用? @SotiriosDelimanolis 我认为new NanoClock() 调用类构造函数并创建对象的实例,然后我可以将其转换为线程。这种做法我已经看过好几次了……有什么问题吗?
  • @AlpayY:你当然是对的。我没有正确阅读整个代码...

标签: java multithreading synchronization shared-memory volatile


【解决方案1】:

您有 两个 NanoClock 实例:其中一个是匿名的 new NanoClock(),因为您的另一个线程中的 Runnable 很高兴在后台保持时间;另一个是nClock,它闲置在主线程的前台。

nClock 应该是那个其他线程中的Runnable

Thread clockThread = new Thread(nClock);  // not new NanoClock()

这可能不是完整的解决方案,但应该是朝着正确方向迈出的一大步。

【讨论】:

  • 就是这样,谢谢!!!有时你只是瞎了眼……这对我很有帮助,非常感谢!
【解决方案2】:

System.currentTimeMillis() 返回一个 long,但你将它存储在一个 double 中,这会导致精度损失。当您将成员时间(以及它的 getter 的返回类型)更改为 long 时,您应该会得到预期的结果。

根据经验:当使用时间单位时,long 是大多数时候最合适的数据类型。浮点数不适合存储精确结果。

【讨论】:

  • 最初这行代码做了别的事情。它将时间转换为 unixtime 格式,所以我需要小数。然而,这不是问题,在 NanoClock 中使用 println 方法时,我得到了正确的结果。我的问题是,run() 不会更新 volatile 时间变量。
  • @AlpayY 这可能是问题的一部分,因为当您将当前时间与时间变量进行比较时,会发生隐式转换。而且我不确定你的情况是否如你所愿。正如其他人指出的那样,您的代码还存在其他问题。所以我的帖子可能只是你问题的一小部分。
【解决方案3】:
Thread.sleep(2000);
System.out.println("Time: " + nClock.getTime());

main() 中的 for 必须是 sleep(2000)

【讨论】:

  • 谢谢!对不起,我在我的实际程序中有这个。我现在改变了这个,我删除了 NanoClock 类中的 sleep 并在 for 循环中添加了一个 sleep(2000),但我仍然得到相同的 double 值。每次迭代。
【解决方案4】:

如果下面的代码需要 2 秒,那么时间会改变。

//MY_ISSUE: This returns the same value every time
for(int a = 0; a < 10; a++) {
    System.out.println("Time: " + nClock.getTime());
}

但是,具有 10 次迭代和 system.out 的 for 循环甚至不会花费一毫秒,因此它不会改变。

为什么是 2 秒?因为你的可运行代码中有一个 Thread.sleep。

Thread.sleep(2000);

也就是说,下一次更新将在 2 秒后进行。

并使用 System.nanoTime() 而不是 System.currentTimeMillis() 因为你真的想要纳米时间而不是毫秒。


更新:

在我的机器上

public static void main(String args[]) {
    long start = System.currentTimeMillis();
    for(int a = 0; a < 10; a++) {
        System.out.println("Iterating " + a);
    }
    long end = System.currentTimeMillis();
    System.out.println("Start = " + start);
    System.out.println("End   = " + end);
}

结果,开始时间和结束时间没有区别

Iterating 0
Iterating 1
Iterating 2
Iterating 3
Iterating 4
Iterating 5
Iterating 6
Iterating 7
Iterating 8
Iterating 9
Start = 1499592836298
End   = 1499592836298

该代码块执行速度如此之快,甚至连一毫秒都用不到。根据时间,可能需要 1 毫秒。

将其更改为 System.nanoTime()

public static void main(String args[]) {
    long start = System.nanoTime();
    for(int a = 0; a < 10; a++) {
        System.out.println("Iterating " + a);
    }
    long end = System.nanoTime();
    System.out.println("Start = " + start);
    System.out.println("End   = " + end);
}

结果,开始时间和结束时间不同。

Iterating 0
Iterating 1
Iterating 2
Iterating 3
Iterating 4
Iterating 5
Iterating 6
Iterating 7
Iterating 8
Iterating 9
Start = 1012518090518837
End   = 1012518091012960

【讨论】:

  • 谢谢,当我发布问题时,我似乎犯了那个错误......我在 NanoClock 的 run() 中删除了 sleep 并在 for 循环中添加了一个 Thread.sleep(2000) .但我总是得到相同的值,所以问题仍然存在。
  • 同样,for 循环甚至不会花费一毫秒。
  • 谢谢,可视化非常有用!即使我的问题在于同时存在的两个 NanoClock 实例,这也是我在尝试测试 NanoClock 类的不同方法时犯的一个错误。
  • 如果您真的只想查看其他代码中的时间变化,请执行以下操作:在您的 for 循环中,为每次迭代添加 Thread.sleep(100)。在您的 run() 方法中,将 Threat.sleep(2000) 更改为 Thread.sleep(10) 并从 catch Exception 中删除 System.exit(0)。时间将每 10ms 更新一次,而循环总共需要 1000ms。你应该改变时间。
猜你喜欢
  • 1970-01-01
  • 2017-03-23
  • 1970-01-01
  • 1970-01-01
  • 2015-03-20
  • 1970-01-01
  • 2017-08-12
  • 2017-03-17
  • 2019-03-11
相关资源
最近更新 更多