无法让 Thread.interrupt 工作
Can't get Thread.interrupt to work
我有一个程序可以执行某些文件 I/O 然后休眠几秒钟,检查文件是否已更改,如果相同则休眠。如果它们已更改,它会执行相同的文件 I/O 然后返回休眠状态。我想实现一个击键,如果按下它会唤醒这个线程,但我无法让线程处理 InterruptedException。我的(简化的)代码在这里:
import java.awt.Color;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class WhosebugExample extends JFrame{
private class MyDispatcher implements KeyEventDispatcher {
boolean keyEventDone = false;
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
if(e.getID() == KeyEvent.KEY_PRESSED){
if((e.getKeyCode() == 80 && e.getModifiers() == 11) && !keyEventDone){
System.out.println("interrupting");
interrupt();
}
}
if (e.getID() == KeyEvent.KEY_RELEASED) {
if(e.getKeyCode() == 80){
keyEventDone = false;
}
}
return true;
}
}
public void interrupt(){
System.out.println("recieved interrupt");
Thread.currentThread().interrupt();
}
public static void main(String[] args){
String fileName = "file Name";
String oldFileName = "oldFileName";
JFrame frame = new WhosebugExample();
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
frame.setSize(217, 104);
do{
if(!fileName.equals(oldFileName)){
}else{
try {
System.out.println("Same file");
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("continuing");
if(Thread.currentThread().isInterrupted()){
System.out.println("continuing");
continue;
}
e.printStackTrace();
}
}
oldFileName = fileName;
}while(true);
}
public WhosebugExample(){
super("");
JPanel pane = new JPanel();
pane.setBackground(Color.LIGHT_GRAY);
setContentPane(pane);
KeyboardFocusManager manager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(new MyDispatcher());
}
}
class 中还有其他内容,但其中 none 与线程或任何内容有关。此外,我知道检查文件名不是执行此操作的最佳方法,但在我的应用程序中,如果文件不同,文件名将始终不同,因为文件名是根据时间生成的。
当我按 "ctrl+shift+alt+p" 唤醒线程时,它会从 MyDispatcher class 打印出 "interrupting" 并从 main [=25= 的中断方法打印出 "recieved interrupt" ],但没有别的,线程一直在休眠
我见过的所有中断休眠线程的例子都有不在主线程中的线程 class。这就是我的不行的原因吗?
同样,您中断了错误的线程,并希望传递正确的线程。例如,获取您的代码:
import java.awt.Color;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
@SuppressWarnings("serial")
public class WhosebugExample extends JFrame {
static String oldFileName = "oldFileName";
private Thread runningThread;
private class MyDispatcher implements KeyEventDispatcher {
boolean keyEventDone = false;
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
if ((e.getKeyCode() == 80 && e.getModifiers() == 11) && !keyEventDone) {
System.out.println("interrupting");
interrupt();
}
}
if (e.getID() == KeyEvent.KEY_RELEASED) {
if (e.getKeyCode() == 80) {
keyEventDone = false;
}
}
return true;
}
}
// pass in the correct thread to interrupt
public void setRunningThread(Thread runningThread) {
this.runningThread = runningThread;
}
public void interrupt() {
System.out.println("recieved interrupt");
// !! Thread.currentThread().interrupt();
runningThread.interrupt();
System.out.println("interrupt Thread id: " + Thread.currentThread().getId());
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
String fileName = "file Name";
WhosebugExample frame = new WhosebugExample();
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
frame.setSize(217, 104);
Thread thread = new Thread(() -> {
do {
if (!fileName.equals(oldFileName)) {
} else {
try {
System.out.println("do-while Thread id: " + Thread.currentThread().getId());
System.out.println("Same file");
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("continuing");
if (Thread.currentThread().isInterrupted()) {
System.out.println("continuing");
continue;
}
e.printStackTrace();
}
}
oldFileName = fileName;
} while (true);
});
// pass in the thread
frame.setRunningThread(thread);
thread.start(); // start it running
});
}
public WhosebugExample() {
super("");
JPanel pane = new JPanel();
pane.setBackground(Color.LIGHT_GRAY);
setContentPane(pane);
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(new MyDispatcher());
}
}
你知道,也许有一种更简单的方法来完成你想做的事情:
- 创建一个每 x 秒重复一次的摆动计时器(我们将在本例中使用 10 秒)
- 在计时器内启动一个新线程,如果我们需要它更直接地与 GUI 交互,可能是一个 SwingWorker,它会检查文件情况并在需要时执行文件 I/O。
- 给计时器一个初始延迟 0,因此它会立即启动或重新启动
- 使用键绑定而不是烦躁的 KeyListener
- 在我们的绑定触发的 Action 中,只需调用 Swing Timer 上的
restart()
,由于初始延迟为 0,它会立即重新启动其操作,然后重新启动 10 秒等待。
类似于:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class WhosebugExample2 extends JPanel {
// 10 seconds between tasks
private static final int TIMER_DELAY = 10 * 1000;
int keyCode = KeyEvent.VK_P;
int modifiers = InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK
| InputEvent.ALT_DOWN_MASK;
private KeyStroke shftCtrlAltP = KeyStroke.getKeyStroke(keyCode, modifiers);
private int condition = WHEN_IN_FOCUSED_WINDOW;
private InputMap inputMap = getInputMap(condition);
private ActionMap actionMap = getActionMap();
private Timer myTimer = new Timer(TIMER_DELAY, new TimerListener());
public WhosebugExample2() {
setPreferredSize(new Dimension(400, 300));
// create key binding
inputMap.put(shftCtrlAltP, shftCtrlAltP.toString());
actionMap.put(shftCtrlAltP.toString(), new MyAction());
// myWorker.execute();
myTimer.setInitialDelay(0);
myTimer.start();
}
private class MyAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Key pressed");
myTimer.restart(); // simply re-start the timer
}
}
private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// launch SwingWorker or other thread to check if files have changed
// and if so do file I/O
System.out.println("Timer running");
}
}
private static void createAndShowGui() {
WhosebugExample2 mainPanel = new WhosebugExample2();
JFrame frame = new JFrame("WhosebugExample2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
此外,您的代码和程序设计当前要求轮询一个文件或多个文件的状态,然后在它们发生变化时执行某些操作。一个更有效的替代方法是根本不轮询,而是使用核心 Java API 的一部分 Java NIO WatchService API,因为 Java 7.
我有一个程序可以执行某些文件 I/O 然后休眠几秒钟,检查文件是否已更改,如果相同则休眠。如果它们已更改,它会执行相同的文件 I/O 然后返回休眠状态。我想实现一个击键,如果按下它会唤醒这个线程,但我无法让线程处理 InterruptedException。我的(简化的)代码在这里:
import java.awt.Color;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class WhosebugExample extends JFrame{
private class MyDispatcher implements KeyEventDispatcher {
boolean keyEventDone = false;
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
if(e.getID() == KeyEvent.KEY_PRESSED){
if((e.getKeyCode() == 80 && e.getModifiers() == 11) && !keyEventDone){
System.out.println("interrupting");
interrupt();
}
}
if (e.getID() == KeyEvent.KEY_RELEASED) {
if(e.getKeyCode() == 80){
keyEventDone = false;
}
}
return true;
}
}
public void interrupt(){
System.out.println("recieved interrupt");
Thread.currentThread().interrupt();
}
public static void main(String[] args){
String fileName = "file Name";
String oldFileName = "oldFileName";
JFrame frame = new WhosebugExample();
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
frame.setSize(217, 104);
do{
if(!fileName.equals(oldFileName)){
}else{
try {
System.out.println("Same file");
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("continuing");
if(Thread.currentThread().isInterrupted()){
System.out.println("continuing");
continue;
}
e.printStackTrace();
}
}
oldFileName = fileName;
}while(true);
}
public WhosebugExample(){
super("");
JPanel pane = new JPanel();
pane.setBackground(Color.LIGHT_GRAY);
setContentPane(pane);
KeyboardFocusManager manager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(new MyDispatcher());
}
}
class 中还有其他内容,但其中 none 与线程或任何内容有关。此外,我知道检查文件名不是执行此操作的最佳方法,但在我的应用程序中,如果文件不同,文件名将始终不同,因为文件名是根据时间生成的。
当我按 "ctrl+shift+alt+p" 唤醒线程时,它会从 MyDispatcher class 打印出 "interrupting" 并从 main [=25= 的中断方法打印出 "recieved interrupt" ],但没有别的,线程一直在休眠
我见过的所有中断休眠线程的例子都有不在主线程中的线程 class。这就是我的不行的原因吗?
同样,您中断了错误的线程,并希望传递正确的线程。例如,获取您的代码:
import java.awt.Color;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
@SuppressWarnings("serial")
public class WhosebugExample extends JFrame {
static String oldFileName = "oldFileName";
private Thread runningThread;
private class MyDispatcher implements KeyEventDispatcher {
boolean keyEventDone = false;
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
if ((e.getKeyCode() == 80 && e.getModifiers() == 11) && !keyEventDone) {
System.out.println("interrupting");
interrupt();
}
}
if (e.getID() == KeyEvent.KEY_RELEASED) {
if (e.getKeyCode() == 80) {
keyEventDone = false;
}
}
return true;
}
}
// pass in the correct thread to interrupt
public void setRunningThread(Thread runningThread) {
this.runningThread = runningThread;
}
public void interrupt() {
System.out.println("recieved interrupt");
// !! Thread.currentThread().interrupt();
runningThread.interrupt();
System.out.println("interrupt Thread id: " + Thread.currentThread().getId());
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
String fileName = "file Name";
WhosebugExample frame = new WhosebugExample();
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
frame.setSize(217, 104);
Thread thread = new Thread(() -> {
do {
if (!fileName.equals(oldFileName)) {
} else {
try {
System.out.println("do-while Thread id: " + Thread.currentThread().getId());
System.out.println("Same file");
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("continuing");
if (Thread.currentThread().isInterrupted()) {
System.out.println("continuing");
continue;
}
e.printStackTrace();
}
}
oldFileName = fileName;
} while (true);
});
// pass in the thread
frame.setRunningThread(thread);
thread.start(); // start it running
});
}
public WhosebugExample() {
super("");
JPanel pane = new JPanel();
pane.setBackground(Color.LIGHT_GRAY);
setContentPane(pane);
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(new MyDispatcher());
}
}
你知道,也许有一种更简单的方法来完成你想做的事情:
- 创建一个每 x 秒重复一次的摆动计时器(我们将在本例中使用 10 秒)
- 在计时器内启动一个新线程,如果我们需要它更直接地与 GUI 交互,可能是一个 SwingWorker,它会检查文件情况并在需要时执行文件 I/O。
- 给计时器一个初始延迟 0,因此它会立即启动或重新启动
- 使用键绑定而不是烦躁的 KeyListener
- 在我们的绑定触发的 Action 中,只需调用 Swing Timer 上的
restart()
,由于初始延迟为 0,它会立即重新启动其操作,然后重新启动 10 秒等待。
类似于:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class WhosebugExample2 extends JPanel {
// 10 seconds between tasks
private static final int TIMER_DELAY = 10 * 1000;
int keyCode = KeyEvent.VK_P;
int modifiers = InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK
| InputEvent.ALT_DOWN_MASK;
private KeyStroke shftCtrlAltP = KeyStroke.getKeyStroke(keyCode, modifiers);
private int condition = WHEN_IN_FOCUSED_WINDOW;
private InputMap inputMap = getInputMap(condition);
private ActionMap actionMap = getActionMap();
private Timer myTimer = new Timer(TIMER_DELAY, new TimerListener());
public WhosebugExample2() {
setPreferredSize(new Dimension(400, 300));
// create key binding
inputMap.put(shftCtrlAltP, shftCtrlAltP.toString());
actionMap.put(shftCtrlAltP.toString(), new MyAction());
// myWorker.execute();
myTimer.setInitialDelay(0);
myTimer.start();
}
private class MyAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Key pressed");
myTimer.restart(); // simply re-start the timer
}
}
private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// launch SwingWorker or other thread to check if files have changed
// and if so do file I/O
System.out.println("Timer running");
}
}
private static void createAndShowGui() {
WhosebugExample2 mainPanel = new WhosebugExample2();
JFrame frame = new JFrame("WhosebugExample2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
此外,您的代码和程序设计当前要求轮询一个文件或多个文件的状态,然后在它们发生变化时执行某些操作。一个更有效的替代方法是根本不轮询,而是使用核心 Java API 的一部分 Java NIO WatchService API,因为 Java 7.