如何在运行循环的同时保证事件线程正常响应不被阻塞
问题原因分析
- 第二版代码逻辑错误:
nativeMousePressed中判断if(program != null)才创建线程,但初始化时program为null,导致首次点击不会创建线程,鼠标松开时直接调用program.interrupt()就会触发空指针异常。 - 第一版代码存在线程复用问题:Java 的
Thread实例仅允许调用一次start()方法,第二次按下鼠标重复调用会抛出IllegalThreadStateException异常。 - 存在线程可见性隐患:
Controller.fixAim没有加volatile修饰,多线程场景下子线程不会主动同步主内存的变量值,就算事件线程修改了fixAim,运行循环的子线程也可能感知不到,导致死循环。 - 最初的事件线程阻塞原因:所有系统事件回调都是运行在专属的事件分发线程上,如果直接在事件回调方法内写死循环,会占满事件线程的执行资源,后续所有鼠标、键盘事件都无法正常分发,自然收不到
nativeMouseReleased回调。
修复方案
第一步:给跨线程访问的静态变量加volatile修饰
修改Controller类中的fixAim定义,保证变量修改对所有线程可见:
public class Controller { // 其他原有代码不变 public static volatile boolean fixAim = false; // 若threeClicked也会跨线程修改,同样加volatile修饰 public static volatile boolean threeClicked = false; }
第二步:修正事件监听器的逻辑
public class NativeMouseEvent implements NativeMouseListener { private Program program; @Override public void nativeMouseClicked(org.jnativehook.mouse.NativeMouseEvent e) { } @Override public void nativeMousePressed(org.jnativehook.mouse.NativeMouseEvent e) { if(e.getButton() == 1 && Controller.threeClicked) { Controller.fixAim = true; // 仅当线程未创建时才初始化启动,和之前的判断逻辑相反 if(program == null) { program = new Program(); program.start(); } } } @Override public void nativeMouseReleased(org.jnativehook.mouse.NativeMouseEvent e) { Controller.fixAim = false; // 先判空再处理,避免空指针 if(program != null) { program.interrupt(); program = null; } } }
第三步:优化子线程的退出逻辑
public class Program extends Thread { @Override public void run() { // 同时判断标志位和线程中断状态,双重保险保证及时退出 while(Controller.fixAim && !isInterrupted()) { System.out.println("test"); // 可根据需求添加休眠控制执行频率,避免占用过多CPU资源 try { Thread.sleep(10); } catch (InterruptedException e) { // 收到中断信号直接退出循环 break; } } } }
内容的提问来源于stack exchange,提问作者user14732842
相关产品推荐
相关产品推荐

