amp@java

amplifier's java blog

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  98 随笔 :: 0 文章 :: 228 评论 :: 0 Trackbacks
做GUI程序的时候,通常有个后台工作线程在努力工作,但是中间又需要一些暂停,而关闭程序的时候,必须立即结束那个线程,退出程序,也有的时候需要停止后台线程,但不关闭程序。例如,做一个目录监控程序,发现目录中有文件的时候,执行一定的操作,执行完之后没有文件了,就要暂停一下,过几秒或几分钟再次检测,这时候就要对线程进行暂停操作,如果在暂停的时候,用户要关闭程序,就必须马上停止线程,如果用户需要暂停检测,按下某个按钮后,需要让线程马上停止,但再次按下某个按钮,线程又必须马上开始。

以前我都是通过检测停止标记和用Thread.sleep(time)来完成的,后台线程的每次循环都要检查停止标记,如果发现停止标记已设定,就不再循环,退出线程,在线程内部,如果需要暂停,就执行Thread.sleep(time)。通过把线程的setDaemon(true)方法,还可以让线程作为后台线程,当图形界面关闭后,线程也自动退出。

但是,这种方式有个问题,如果我需要在图形界面上点击按钮来停止线程,但并不退出程序,而点击按钮的时候线程正处于sleep状态,就对它没有任何办法,只能让它醒过来再操作,如果sleep的时间比较长,例如1分钟,那么点击按钮之后,用户最多要等1分钟才能把线程停下来。当然,Thread对象有个interrupt方法,但是已经被标记为过期,一般不建议使用了。感谢评论中watchzerg的提醒,Thread的interrupt()并没有标记为过期,可以按照他的说法来操作,更为简单。

怎么让线程能暂停,又能随时叫醒呢?原来Java里最原始的对象Object就自带此功能。

每个Object都有wait(time)和notify()方法,前者就是让拥有该Obejct的线程处于暂停状态,后者则让线程马上唤醒,通过这两个方法,就能够满足上述的所有要求。

首先,建立一个同步对象:
Object syncObj = new Object();

然后在线程中需要暂停的地方,调用该对象的wait(time)方法:
synchronized (syncObj) {
       syncObj.wait(60*1000);
}

在图形界面的按钮监听事件中,对该对象执行notify()方法:
        button_1.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {

                thread.setStop(true);
                synchronized (syncObj) {
                        syncObj.notify();
                 }
                //为了等待线程退出,还可以加上以下语句:
                thread.join();

            }
        });



posted on 2015-03-10 16:52 amp@java 阅读(5838) 评论(2)  编辑  收藏 所属分类: Java common

评论

# re: 如何让线程暂停,又能随时唤醒? 2015-03-31 10:26 watchzerg
自己定制停止标志位这种方法是有很多不妥的。《effective java》里也很早就说过“当线程在sleep时,无法检测停止标志位”这种缺陷。作者的建议是在循环中使用“检测Thread.currentThread().isInterrupted()”来代替“检测自定义的停止标志位”,需要终止该线程的时候直接调用该线程的interrupt()方法,这样不管这个线程是sleep还是在检测循环,都可以几乎立即优雅的终止执行。  回复  更多评论
  

# re: 如何让线程暂停,又能随时唤醒? 2015-04-02 16:48 amp@java
@watchzerg
非常感谢,原来我记错了,我还以为interrupt()方法已经被标记为过期了。  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: