在我们用JAVA做客户端的时候,可能会遇上这么一个需求:停止当前正在执行的一个操作。
这个操作或者操作时间过长而让客户不想等待它,从而要停止它的执行。那这个操作怎么做呢?
我们都知道,我们在使用事件触发来执行一个业务方法,一般需要使用一个新的线程,否者当前的UI线程会卡死,以Swing为例,JButton被点击后触发事件的代码:
btn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { new Thread(new Runnable() { @Override public void run() { //执行业务方法 System.out.println("执行。这个方法要执行很久!!"); } }).start(); } });
那么我们要取消执行这个方法,最好最直接的做法就是停掉它。
所以我们要想一个办法来管理这些线程,在这里我没有使用线程池来管理,而是适用一个List来管理。
private static LinkedList<Thread> threadList = new LinkedList<Thread>(); public static LinkedList<Thread> getThreadList() { return threadList; }
为什么要用LinkedList?因为它可以快速的找到头尾元素,从而提高性能。这里List我用它来装着每一个由UI启动的执行业务方法的线程。
loginBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("登陆。。这个方法要执行5秒"); } }); thread.start(); //开始执行 threadList.add(thread); //把线程放到List里 } });
既然把线程放在了List里,那要停止它很简单,把它找到,然后调用stop()方法:
private void stopBtnActionPerformed(ActionEvent e) { Thread thread = null; try{ thread = threadList.getLast(); thread.stop(); System.out.println("操作被已手动停止"); }catch(NoSuchElementException ex){ System.out.println("没有正在执行的操作!"); }catch(Exception exx){ exx.printStackTrace(); }finally{ threadList.remove(thread); //从List移除这条线程。 } }
为了防止stop()方法调用时报错,我们需要写一个扫描器来扫描哪些线程run()方法是已经执行完毕而不能调用stop()方法,run()方法执行完毕的线程就把它从List移除
import java.lang.Thread.State; import java.util.LinkedList; import com.alee.utils.ThreadUtils; /** * 保存每个执行操作的线程,并且定期清理已经结束的线程。 * 主要用于“取消上次操作”功能。 * @author g * */ public class ThreadListScaner implements Runnable{ private LinkedList<Thread> threadList; public ThreadListScaner(){ this.threadList = UIContext.getThreadList(); } @Override public void run() { //2秒扫描一次 while(true){ ThreadUtils.sleepSafely(2000); LinkedList<Thread> tempThreadList = new LinkedList<Thread>(threadList); for(Thread thread : tempThreadList){ State state = thread.getState(); if(state.equals(State.TERMINATED)){ //如果是TERMINATED状态,则移除这条线程 threadList.remove(thread); } } } } }
这里我把装线程的List缓存到一个叫UIContext的类里,其实就是一个装在各种全局可能需要用到的东西的类。
这个代码实现了一个功能:停止上一操作,每按一次停止按钮,就停止一条线程。