Java:易失性变量未更新(get 和 set 方法无效)

Java: Volatile variable not updating (get and set methods not working)

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

这个 class 还有一个 getTime() 方法,它 returns double 值。另一个class(Master")正在构造NanoClockclass并创建一个线程,同时调用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);
        }
    }
}

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

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

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

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

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

为什么是 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
Thread.sleep(2000);
System.out.println("Time: " + nClock.getTime());

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

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

nClock 应该 是另一个线程中的 Runnable

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

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