这一要求出现在我的Android应用程序中,但它一般适用于Java。我的应用程序“做些什么”每几秒钟。我已经按照以下方式实现了这一点(只是相关的片段-不是完整的代码):
Snippet1:
public class PeriodicTask {
private boolean running = true;
private int interval = 5;
public void startTask(){
while (running){
doSomething();
try{
Thread.sleep(interval * 1000);
} catch(InterruptedException e){
//Handle the exception.
}
}
}
public void stopTask(){
this.running = false;
}
public void setInterval(int newInterval){
this.interval = newInterval;
}
}正如您所看到的,这种方法的问题是setInterval()不能立即生效。只有在以前的睡眠()完成之后,它才会生效。
由于我的用例允许最终用户以固定的步骤(1秒-从1到60秒)设置时间间隔,所以我将实现修改为在循环中休眠;并且每秒钟检查一次新的间隔值如下:
Snippet2:
public class PeriodicTask {
private boolean running = true;
private int interval = 5;
private int loopCounter = 0;
public void startTask(){
while (running){
doSomething();
try{
while(loopCounter < interval) {
Thread.sleep(1 * 1000);
loopCounter ++;
}
} catch(InterruptedException e){
//Handle the exception.
}
}
}
public void stopTask(){
this.running = false;
}
public void setInterval(int newInterval){
synchronized (this) {
this.interval = newInterval;
if(newInterval < loopCounter){
loopCounter = 0;
}
}
}
}是否有理由不使用这种方法?
我最近遇到了用于这个目的的interrupt()方法。但是,我不知道怎么用它。首先,与睡眠方法不同的是,中断方法不是static。那么,我该打断什么Thread呢?
public void setInterval(int newInterval){
this.interval = newInterval;
//What thread do I call interrupt() on?
}其次,如果我成功地中断了休眠的Thread,我相信将执行InterruptedException的catch块。但是,此时我需要再次调用startTask()。我对这一递归的终止感到困惑。关于中断()的使用,我已经问过几个问题,但是找不出对我有帮助的任何东西。
有什么指示吗?
编辑-关于确切要求的更多细节:
我的应用程序每隔几秒钟就使用REST调用获取一些值。用户可配置更新间隔。
现在,假设更新间隔设置为60秒。我发布的Snippet1将工作(错误)如下:
PeriodicTask才会看到新的更新间隔。确切的要求是,新的更新间隔应该立即生效(或者至少在设置后的1秒内生效,因为这是用户可能会感知到的)。
我的Snippet2和Snippet3是实现这一要求的尝试。
发布于 2012-01-04 13:42:57
这的回答帮助我完成了这项工作。发布一些关于我是如何实现它的代码。特别重要的是startTask()和setInterval()。
public class PeriodicTask {
private volatile boolean running = true;
private volatile int interval = 5;
private final Object lockObj = new Object();
public void startTask() {
while (running) {
doSomething();
synchronized (lockObj) {
try{
lockObj.wait(interval * 1000);
} catch(InterruptedException e){
//Handle Exception
}
}
}
}
public void stopTask() {
this.running = false;
}
public void setInterval(int newInterval) {
synchronized (lockObj) {
this.interval = newInterval;
lockObj.notify();
}
}
}发布于 2012-01-04 06:15:26
我不清楚你到底想做什么。您的目标是停止在PeriodicTask中运行循环的线程,还是只想中断循环并允许线程继续?如果您只想中断循环,但允许线程继续,请考虑以下示例:
public class ThreadStopExample {
public static void main ( String[] args ) throws InterruptedException {
final PeriodicTask task = new PeriodicTask ();
Thread t = new Thread ( new Runnable () {
@Override
public void run () {
System.out.println ( Thread.currentThread ().getName ()
+ " starting" );
task.startTask ();
System.out.println ( Thread.currentThread ().getName ()
+ " done with the periodic task" );
}
} );
t.start ();
Thread.sleep ( 12000 );
task.setInterval ( 1 );
Thread.sleep ( 3000 );
task.stopTask ();
}
static class PeriodicTask {
private volatile boolean running = true;
private volatile int interval = 5;
public void startTask () {
running = true;
while ( running ) {
doSomething ();
try {
int count = 0;
while ( running && count++ < interval ) {
Thread.sleep ( 1000 );
}
} catch ( InterruptedException e ) {
Thread.currentThread ().interrupt ();
running = false;
break;
}
}
}
public void stopTask () {
running = false;
}
public void setInterval ( int newInterval ) {
interval = newInterval;
}
private void doSomething () {
System.out.println ( "[" + Thread.currentThread ().getName ()
+ "] Interval: " + interval );
}
}
}这与您现有的代码非常相似。请注意易失性字段,以确保运行PeriodicTask循环的线程与试图更改间隔和停止任务的主线程之间的正确同步(有关java内存模型的更多信息,请参见这里链接)。如您所见,在调用停止任务之后,与PeriodicTask实例一起工作的线程仍在继续。另外,请注意,PeriodicTask将在当前线程收到中断异常时调用中断。这确保在当前线程上设置中断标志,以便任何外部代码都能够看到中断并作出适当反应,例如,运行PeriodicTask的线程可能检查了自己的中断状态并做了一些有趣的事情,而不是打印已完成。
如果您的目标是停止线程本身,那么您可能希望让PeriodicTask扩展线程,这是不建议的,除非您有充分的理由这样做,或者让PeriodicTask实现可运行。考虑下一个例子:
public class ThreadStopExample2 {
public static void main ( String[] args ) throws InterruptedException {
final PeriodicTask task = new PeriodicTask ();
Thread t = new Thread ( task );
t.start ();
Thread.sleep ( 12000 );
task.setInterval ( 1 );
Thread.sleep ( 3000 );
t.interrupt ();
}
static class PeriodicTask implements Runnable {
private volatile int interval = 5;
@Override
public void run () {
while ( true ) {
doSomething ();
try {
int count = 0;
while ( count++ < interval ) {
Thread.sleep ( 1000 );
}
} catch ( InterruptedException e ) {
Thread.currentThread ().interrupt ();
break;
}
}
}
public void setInterval ( int newInterval ) {
interval = newInterval;
}
private void doSomething () {
System.out.println ( "[" + Thread.currentThread ().getName ()
+ "] Interval: " + interval );
}
}
}在这里,PeriodicTask处于一个繁忙的循环中,直到运行它的线程被中断。中断用于向PeriodicTask发出退出循环的信号,然后该循环允许线程通过run方法的结束而完成。
关于两个明确的问题:不,如果您不打算控制正在执行的线程,我不认为使用PeriodicTask的方式有任何真正的问题,例如,可能PeriodicTask的实例是由池中的一个线程运行的(但是一定要修复您的代码才能正确地同步),在使用中断时,您可以在要中断的线程的实例上调用它。如何获得对该线程的引用取决于系统。
发布于 2012-01-03 06:04:29
在正在休眠的线程上调用interrupt(),它将抛出在catch块中处理的InterruptedException。然后,你有了新的间隔,你可以绕圈,然后回去睡觉。如果您捕获并处理InterruptedException,则不会再发生任何事情。
让我提供几个创建和中断线程的例子链接,因为从您的评论中您似乎缺少了一些重要的想法。请仔细回顾这些,然后你应该理解标准的方式去做你想要的。
http://docs.oracle.com/javase/tutorial/essential/concurrency/simple.html http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html
https://stackoverflow.com/questions/8708473
复制相似问题