今天我使用TimerTask
创建了一个超时作业,但遇到了一个新问题,我有一个static volatile boolean
变量flag
。我的理解是,一旦此变量的值发生变化,所有正在运行的thread
都会通知它。但是当我运行这个程序时,我得到的输出低于输出值。
O / P:
--------------
--------------
DD
BB
Exiting process..
CC
我的期望是我的最后一次打印应该退出过程.. 为什么这种奇怪的行为?
我的代码是:
public class TimeOutSort {
static volatile boolean flag = false;
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
flag = true;
System.out.println("Exiting process..");
// System.exit(0);
}
}, 10 * 200);
new Thread(new Runnable() {
@Override
public void run() {
while (!flag)
System.out.println("BB");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (!flag)
System.out.println("CC");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (!flag)
System.out.println("DD");
}
}).start();
}
}
编辑:我如何实现这一目标?
答案 0 :(得分:3)
volatile
几乎意味着每次线程访问变量时,必须确保使用每个线程可见的版本(即没有每线程缓存)。
强制CC打印线程在 另外:请注意,打印到flag
设置为true
后实际上立即运行。完全可能(特别是在单核机器上)一个线程设置标志并且在 CC-printing线程之前打印消息甚至有机会运行。< / p>
System.out
涉及获取锁(在println()
调用内的某个位置),这可以修改测试代码的多线程行为。< / p>
答案 1 :(得分:3)
线程可以按任何顺序执行代码
thread BB: while (!flag) // as flag is false
thread Main: flag = true;
thread Main: System.out.println("Exiting process..");
thread BB: System.out.println("BB");
我的期望是我的最后一次印刷应该是退出流程..
线程旨在同时独立运行。如果这始终是最后一个语句,那将是令人惊讶的,因为当你设置标志时你无法确定每个线程的位置。
答案 2 :(得分:1)
打印出“CC”的线程在打印出“退出进程...”的线程打印之后才发生接收任何CPU时间。这是预期的行为。
答案 3 :(得分:1)
它没有挥发不工作(如果不是,你的一些线程不会停止)。它是关于不同线程中指令执行的顺序,这是随机的(取决于OS调度),除非您在中间步骤显式同步循环。
答案 4 :(得分:1)
要为您获得的解释添加替代措辞:在示例输出中,打印"CC"
的线程被暂停(某处)“介于之间”while (!flag)
行和System.out.println()
。这意味着在它唤醒后,println()
在下一次检查标志之前执行。 (它也不会因为你改变标志值而被唤醒,但是因为其他一些线程会阻塞或耗尽它的时间片。)
答案 5 :(得分:0)
我没有测试它,但你可以像这样实现它
public class TimeOutSort {
static volatile boolean flag = false;
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
synchronized(flag){
flag = true;
notifyAll();
}
}
}, 10 * 200);
new Thread(new Runnable() {
@Override
public void run() {
synchronized(flag){
if(!flag)
{
wait();
}
System.out.println("BB");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized(flag){
if(!flag)
{
wait();
}
System.out.println("CC");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized(flag){
if(!flag)
{
wait();
}
System.out.println("DD");
}
}
}).start();
}
}