gpt4 book ai didi

java - 当后台线程运行时,如何在 jpanel 中显示时间?

转载 作者:行者123 更新时间:2023-12-01 10:49:01 25 4
gpt4 key购买 nike

我试图在后台线程执行昂贵的操作时在 jpanel 中显示时间。显然时间线程应该获得比后台线程更高的优先级才能准确显示时间。

我已经编写了以下解决方案,但我确信它可以做得更好。您有什么建议?

另外:如何在不使用 .stop() 的情况下正确关闭后台线程?

编辑:在没有优先级设置的情况下测试该程序后,它也可以工作,但我真的不知道为什么。

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.WindowConstants;

public class Test1 extends JPanel{

private static final long serialVersionUID = 1L;

private int time = 23*3600+59*60+30;

private Thread operationThread;

public Test1(){
JLabel text = new JLabel();

Timer timeDisplayer = new Timer(1000, e -> {
//Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
text.setText((time/3600)%24+":"+(time/60)%60+":"+(time%60));
time+=1;
});
timeDisplayer.setInitialDelay(0);

JButton b = new JButton("Restart operation");
b.addActionListener(arg0 -> makeNewThread());

add(b);
add(text);

timeDisplayer.start();
}

private void makeNewThread(){
if(operationThread!=null && operationThread.isAlive())
operationThread.stop();
operationThread = new Thread(() -> {
//Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
//expensiveOperation();
});
operationThread.start();
}

public static void main(String[] args){
JFrame f = new JFrame();
Test1 t = new Test1();
f.setLocation(400,50);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.setSize(100,100);
f.setContentPane(t);
f.setVisible(true);
}
}

最佳答案

通常,您显示的内容(例如计时器)不必刷新得那么快就能获得视觉上吸引人的内容。一秒的延迟对于计算机来说是一个巨大的时间量,因此没有必要为计时器更新线程提供额外的优先级。

您的使用情况如果 swing Timer类(class)可以显着提高。计时器的工作方式是向您的处理程序触发一个 ActionEvent,该处理程序在事件分派(dispatch)线程上排队。这意味着事件触发和监听器执行之间可能存在延迟。处理这个问题的更好方法是存储 System.currentTimeMillis 的值。某处并在回调中使用它:

...

private long startMillis;

public Test1()
{
...

Timer timeDisplayer = new Timer(1000, e -> {
time = (System.currentTimeMillis() - startMillis + 500L) / 1000L;
text.setText(((time / 3600) % 24) + ":" + ((time / 60) % 60) + ":" + (time % 60));
});
timeDisplayer.setInitialDelay(0);

...

startMillis = System.currentTimeMillis()
timeDisplayer.start();
}

这还有一个额外的优点,您可以根据需要加快计时器的速度,添加亚秒精度等。如果您决定这样做,最好尽可能延迟时间计算,例如,通过重写显示时间的组件的 paintComponent() 方法。

就停止线程而言,我建议使用一种简单的基于中断的机制来避免使用已弃用的 stop() 方法。不要使用 stop(),而是使用 interrupt()在昂贵的计算线程上。这通常会(但阅读文档)执行以下两件事之一:

  1. 在计算线程中引发中断异常。
  2. 设置线程的中断状态。

然后你的计算的工作就是响应这两种情况。通常,您会将昂贵的部分包含在 try-catch block 中,并尝试定期检查中断状态。这是一个例子:

private expensiveOperation()
{
try {
for(SomeObject among : millionsOfItems) {
// Do stuff
if(Thread.currentThread().interrupted()) {
// Possibly log the interruption as you would for the exception
break;
}
}
} catch(InterruptedException ie) {
// Probably just ignore or log it somehow since this is really a normal condition
} finally {
// If your thread needs special cleanup, this is the place to put it
// This block will be triggered by exceptions as well as breaks
}
}

您可以使用interrupted()检查线程的中断标志。或isInterrupted() 。它们之间唯一真正的区别是前者在检查时清除中断状态,而后者则不会。如果您只想进行一次性检查并让线程死亡,那么使用哪一个并不重要。

这种机制的优点是,它比调用 stop() 为您提供了更多的控制权,特别是当您的线程需要特殊清理时。

关于java - 当后台线程运行时,如何在 jpanel 中显示时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34028929/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com