Java:不更新的易失性变量(获取和设置方法不起作用)

时间:2017-07-09 08:14:05

标签: java multithreading synchronization shared-memory volatile

我有一个Runnable" NanoClock"继续在其run()方法中更新私有volatile double值的类。

此类还有一个getTime()方法,它返回double值。另一个类(" 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);
        }
    }
}

4 个答案:

答案 0 :(得分:1)

您有两个 NanoClock个实例:其中一个是匿名new NanoClock(),因为您的其他帖子中的Runnable很乐意保留时间在背景中;另一个是nClock,它在主线程的前台闲置着。

nClock 应该是该另一个帖子中的Runnable

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

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

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

如果下面的代码需要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

答案 3 :(得分:0)

SELECT * FROM table_name WHERE approved=0

Thread.sleep(2000); System.out.println("Time: " + nClock.getTime()); 中的for必须为main()