如何正确管理单线程执行?

时间:2016-10-30 20:17:23

标签: java multithreading concurrency executorservice single-threaded

我有一个流程,我希望由不同的来源触发。

假设我们有一个案例,我们在某些条件下有一些其他过程(让我们称之为“manualStarter”)想触发这个主要过程。主要过程需要一段时间才能完成,比方说10秒到10分钟。如果在manualStarter尝试启动过程时进程已在进行中,则不应将其排队多次。触发主进程启动的第二个进程可能是“timedStarter”,它会偶尔触发进程,但只有当进程没有运行时,否则它不会将进程排队,而是会尝试再过一段时间。

现在我尝试使用isAlive()和join()来实现这种进程管理器,但似乎isAlive()根本不可靠,直到它将其状态更改为alive,此线程的100个线程可能会开始(有时也会)。所以我似乎不能依赖它。

然后我尝试使用更接近我正在寻找的SingleThreadExecutor服务,它没有阻止任何东西,它只允许一个线程执行该过程,所以这很好,但我仍然不知道如何检查状态/正确锁定它,或者我怎样才能确保启动线程的队列不会大于1.我读了一下信号量通常用于类似的任务,但我不知道如何我可以在这种情况下使用它们。

那我怎么能实现我想要的呢?我需要实现自己的ThreadPoolExecutor吗?我该怎么做?还有更好的办法吗?

2 个答案:

答案 0 :(得分:1)

您应该使用ExecutorService。有几种可用的实现(包括ScheduledExecutorService,允许您安排自定义和/或重复任务 - 检查Executors)。只需选择最符合您需求的一个。

至于条件执行,任务很简单。定义某种可访问的标志,用于保存当前的#34;状态"给定的任务。如果它正在运行 - 什么也不做,如果它没有运行 - 安排执行。

简单示例:

//our flag 
private volatile AtomicBoolean isRunning=new AtomicBoolean(false);

public void scheduleTask(){
    if(isRunning.get()){
        return; // do nothing
}else{
    synchronized(isRunning){
     if(isRunning.get()){
      return;
}else{
     isRunning.set(true)
    scheduleNewTask();
}
}
}
}

对于任何操作方法,请检查official Oracle's documentaion about Executors. 我在这个例子中使用了AtomicBoolean来模拟" mutable"布尔值。这也可以使用boolean来完成,但需要在不同的对象上进行同步(例如,专用private Object lock=new Object();

答案 1 :(得分:1)

只需使用共享标志,以便手动启动器知道线程是否正在运行。例如:

ScheduledExectorService sched = Executors.newScheduledThreadPool(1);
ManualStarter starter = new ManualStarter();
// Every 10 seconds will check if MainProcess is running and will start
// it if it's not
sched..scheduleAtFixedRate(starter, 0, 10, SECONDS);

然后在某个地方你安排主要的事情定期运行:

{{1}}