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
")正在构造NanoClock
class并创建一个线程,同时调用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()
这可能不是完整的解决方案,但应该是朝着正确方向迈出的一大步。
我有一个 Runnable“NanoClock
”class,它在其 run()
方法中不断更新一个私有的 volatile double 值。
这个 class 还有一个 getTime()
方法,它 returns double 值。另一个class(Master
")正在构造NanoClock
class并创建一个线程,同时调用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()
这可能不是完整的解决方案,但应该是朝着正确方向迈出的一大步。