在周期性运行的线程中自动执行代码
我有一个定期执行代码的线程, G。每10秒钟一次。我希望可以选择以自发方式调用相同的代码,而不必等待10秒钟。但是自动执行和自发执行的代码不能同时运行,如果用户在调用相同方法时按下执行按钮,它们应该按顺序运行。在周期性运行的线程中自动执行代码
有没有人知道一个好的模式,甚至可以解决这种需求的类?
首先想到的是使工作方法同步。但是在这种情况下,手动执行(例如按下按钮)被阻塞,并且必须等待直到线程中的方法结束。有没有更好的方法没有阻塞?
实施例:
public class Executor extends Thread {
// endless loop, executes work method periodically with pause inbetween
@Override
public void run() {
while(true) {
work("automatic");
pause(10000);
}
}
// Working method that's executed periodically or manually
private synchronized void work(String text) {
System.out.println("Working " + text + " " + System.currentTimeMillis());
}
// helper method that pauses the thread
private static void pause(long sleepMs) {
try {
Thread.sleep(sleepMs);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// start automatic execution
Executor executor = new Executor();
executor.start();
// pause a while
pause(1000);
// manual execution
executor.work("manual");
}
}
编辑:解我的要求:
public class ScheduledExecutor {
public static void main(String[] args) throws InterruptedException {
ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1);
executor.scheduleWithFixedDelay(new Work("auto"), 0, 10, TimeUnit.SECONDS);
Thread.sleep(1000);
executor.execute(new Work("manual"));
}
public static class Work implements Runnable {
String text;
public Work(String text) {
this.text = text;
}
@Override
public void run() {
System.out.println("Working " + text + " " + System.currentTimeMillis());
}
}
}
我会创造一个新的,单独的线程执行服务:
ExecutorService executorService = Executors.newFixedThreadPool(1);
然后,我会成立哺养executorService
任务每10秒一次的计时器。
new Timer(10000, new ActionListener {
public void actionPerformed(ActionEvent evt) {
executorService.execute(() -> doWhatever());
}
}).start();
最后,你可以在你按下按钮的处理程序,或其他任何地方,你想在你的代码中调用executorService.execute(() -> doWhatever());
。
只有一次激活doWhatever()
会一次运行,因为executorService
只有一个线程可以运行它们。而且,您的按钮按下处理程序将永远不必等待,因为它只是在队列中放置一个新对象。
谢谢!这让我走向了正确的方向。而不是使用'ScheduledThreadPoolExecutor'并使用'scheduleWithFixedDelay'调用工作方法的Timer与我的需求更好地匹配。 – Roland
我有其周期性地执行代码的线程,即G。每10秒钟一次。我希望可以选择以自发方式调用相同的代码,而不必等待10秒钟。
一种简单的方法在你的代码来做到这一点并不用Thread.sleep(...)
而是做wait(...)
暂停。然后,只要你想让命令唤醒并手动运行,它就会执行一个notify()
。
所以,你的代码看起来是这样的:
while(true) {
work("automatic");
synchronized (this) {
try {
// wait for a bit but allow someone else to awake us to run manually
wait(10000);
} catch (InterruptedException ie) {
// always a good pattern
Thread.currentThread().interrupt();
return;
}
}
}
然后,当你想拥有它的手动运行你这样做:
synchronized (executor) {
executor.notify();
}
的通知将立即唤醒线程,以便它可以运行这是任务。那么工作方法不需要是,因为只有Executor
线程正在运行它。
注:正如指出的@shinobi,使用wait()
这样可以从虚假的唤醒,可与某些操作系统线程实现发生受苦。
最后,制作Executor
implement Runnable
as opposed to extending Thread
是一种更好的做法。
共享服务器线程(执行任务的名称)和客户端线程(需要触发立即执行的那些)之间的信号:
Semaphore sem = new Semaphore(0);
服务器线程需要执行下面的代码(请注意,这是一个无限循环—你可能会想插件程序终止支票的条件while()
):
while(true) {
try {
sem.tryAcquire(10, TimeUnit.SECONDS);
} catch(InterruptedException e) {
continue;
}
runTask();
sem.drainPermits();
}
然后,为了触发立即执行,客户端线程需要这样做:
sem.release();
因此,服务器线程将尽快为客户端线程释放一个(触发立即执行)或定时出在Semaphore.tryAcquire()
(定期执行的10秒后要么取得从信号量许可证执行任务从头开始。)执行间隔10s 开始启动将采取一些稍微更多的涉及逻辑,以及跟踪上次执行的开始时间,但基本思路保持不变。
为了避免多次背靠背执行任务,每次都需要排空许可证,以防在执行过程中立即执行时触发执行。
中断睡眠? –
如果线程在非休眠模式下被中断会发生什么? – Roland
您是否可以更新您的问题以清楚说明您希望如何工作。你说你不希望手动和自动的线程代码同时运行。然后你说你不想在按下按钮时手动执行被阻止...... – Allan