Java:同步ScheduledExecutorService上的两个调度线程
我想创建一个程序: 做一个长时间运行的任务,比如说ChildJob 暂停主要任务ChildJob,并每隔几秒钟提交完成的工作 我提出了这段代码,它安排了两个线程,每几秒钟提交一次提交部分目前是一个sop语句,并且并行运行ChildJob 我面临的问题是,我无法正确地同步这两个线程 在调用commit时,ChildJob线程将继续处理。如何让ChildJob线程等待? 我理解使进程方法同步不是一个选项,因为在这种情况下,提交作业甚至不会运行Java:同步ScheduledExecutorService上的两个调度线程,java,multithreading,thread-synchronization,scheduledexecutorservice,Java,Multithreading,Thread Synchronization,Scheduledexecutorservice,我想创建一个程序: 做一个长时间运行的任务,比如说ChildJob 暂停主要任务ChildJob,并每隔几秒钟提交完成的工作 我提出了这段代码,它安排了两个线程,每几秒钟提交一次提交部分目前是一个sop语句,并且并行运行ChildJob 我面临的问题是,我无法正确地同步这两个线程 在调用commit时,ChildJob线程将继续处理。如何让ChildJob线程等待? 我理解使进程方法同步不是一个选项,因为在这种情况下,提交作业甚至不会运行 import java.util.concurrent.
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.Random;
import java.util.Date;
class Main {
// Processing thread, commiting thread
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
public static void main(String[] args) {
Main app = new Main();
ChildJob workUnit = new ChildJob();
Thread childJobThread = new Thread(new Runnable()
{
@Override
public void run()
{
System.out.println("childJobThread: "+ Thread.currentThread().getName()+" Start. Time = " + new Date());
try{ workUnit.process(); }
catch(InterruptedException e){ e.printStackTrace(); }
}
});
Thread committerThread = new Thread(new Runnable()
{
@Override
public void run()
{
try{ workUnit.commit(); }
catch(InterruptedException e){ e.printStackTrace(); }
}
});
final ScheduledFuture<?> commitHandle = app.scheduler.scheduleAtFixedRate(committerThread, 1, 8, TimeUnit.SECONDS);
final ScheduledFuture<?> jobHandle = app.scheduler.schedule(childJobThread, 0, TimeUnit.SECONDS);
/*
Makes the commitHandle run for 60 * 60 seconds, not needed, manually terminating currently.
app.scheduler.schedule(new Runnable() {
public void run() {
commitHandle.cancel(true);
}
},
60 * 60, TimeUnit.SECONDS);*/
}
}
class ChildJob {
private int i = 0;
public void process() throws InterruptedException
{
// synchronized(this)
// {
while(true) {
System.out.println("ChildJob processing at: " + Thread.currentThread().getName() + " : " + new Date() + "----------: " + i++);
Thread.sleep(1000);
}
//}
}
public void commit() throws InterruptedException
{
synchronized(this)
{
System.out.println("\ncommitterThread: " + Thread.currentThread().getName()+" Start. Time = " + new Date());
// 3s sleep to check consistency from processing.
Thread.sleep(3000);
System.out.println("committerThread: " + Thread.currentThread().getName()+" End. Time = " + new Date() + "\n");
}
}
}
预期结果:
childJobThread: pool-1-thread-1 Start. Time = Mon May 13 17:51:31 IST 2019
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:31 IST 2019----------: 0
committerThread: pool-1-thread-2 Start. Time = Mon May 13 17:51:32 IST 2019
committerThread: pool-1-thread-2 End. Time = Mon May 13 17:51:35 IST 2019
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:35 IST 2019----------: 1
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:36 IST 2019----------: 2
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:37 IST 2019----------: 3
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:38 IST 2019----------: 4
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:39 IST 2019----------: 5
committerThread: pool-1-thread-2 Start. Time = Mon May 13 17:51:40 IST 2019
committerThread: pool-1-thread-2 End. Time = Mon May 13 17:51:43 IST 2019
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:44 IST 2019----------: 6
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:45 IST 2019----------: 7
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:46 IST 2019----------: 8
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:47 IST 2019----------: 9
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:48 IST 2019----------: 10
同时尝试同步,例如:
whiletrue{
同步这个
{
System.out.printlnChildJob处理地址:+Thread.currentThread.getName+:+新日期+------:+i++;
线程1000;
}
}
}
我们的想法是,委员会应该有机会进入工作的运行
样本输出
childJobThread: pool-1-thread-1 Start. Time = Mon May 13 20:42:46 CST 2019
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:46 CST 2019----------: 0
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:47 CST 2019----------: 1
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:48 CST 2019----------: 2
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:49 CST 2019----------: 3
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:50 CST 2019----------: 4
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:52 CST 2019----------: 5
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:53 CST 2019----------: 6
committerThread: pool-1-thread-2 Start. Time = Mon May 13 20:42:54 CST 2019
committerThread: pool-1-thread-2 End. Time = Mon May 13 20:42:57 CST 2019
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:57 CST 2019----------: 7
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:58 CST 2019----------: 8
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:59 CST 2019----------: 9
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:00 CST 2019----------: 10
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:01 CST 2019----------: 11
committerThread: pool-1-thread-2 Start. Time = Mon May 13 20:43:02 CST 2019
committerThread: pool-1-thread-2 End. Time = Mon May 13 20:43:05 CST 2019
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:05 CST 2019----------: 12
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:06 CST 2019----------: 13
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:07 CST 2019----------: 14
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:08 CST 2019----------: 15
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:09 CST 2019----------: 16
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:10 CST 2019----------: 17
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:11 CST 2019----------: 18
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:12 CST 2019----------: 19
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:13 CST 2019----------: 20
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:14 CST 2019----------: 21
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:15 CST 2019----------: 22
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:16 CST 2019----------: 23
为什么要暂停线程并从另一个线程提交?您只需从ChildJob线程进行提交即可—更简单、更可靠。因为,我需要使提交事件基于时间保持一致。比如说,每n秒。而ChildJob.process方法可以根据处理量进行放大或缩小,因此在代码中没有可以放置提交代码的地方。我正在尝试实现一种检查点/自动保存功能。这根本不起作用。更好的方法是使用内置原语,如可重入锁、condvars、锁存器等。但是,通过在一个线程中执行所有操作,完全避免同步问题更好。多线程的好处是可以进行并行处理。如果同步并序列化处理,只会增加复杂性并失去好处。因此这是毫无意义的。@SvetlinZarev抱歉,我不太确定“根本不起作用”部分。在我的笔记本电脑上运行良好,“提交”在“作业”运行之间运行,“提交”期间没有“作业”运行。我认为这绝对是OP想要的。一个周期性地解锁然后立即再次锁定的循环会导致线程饥饿。@SolomonSlow我承认这不是解决这个问题的最佳方案,但它是有效的。我还认为这种简单的方法有助于OP理解这一点,这是一种选择。基于时间的解决方案本质上是不可靠的。想象一下,您在快速服务器类机器和raspberry pi上运行相同的应用程序。在服务器上,它每秒可以处理100k个元素,但在ePi上,它每秒可以处理少于1个元素。您看到基于时间的提交的问题了吗?此外,如果计时器线程因RuntimeException而失败,它将永远不会被重新调度,因此它将永远不会调用commmit
childJobThread: pool-1-thread-1 Start. Time = Mon May 13 20:42:46 CST 2019
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:46 CST 2019----------: 0
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:47 CST 2019----------: 1
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:48 CST 2019----------: 2
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:49 CST 2019----------: 3
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:50 CST 2019----------: 4
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:52 CST 2019----------: 5
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:53 CST 2019----------: 6
committerThread: pool-1-thread-2 Start. Time = Mon May 13 20:42:54 CST 2019
committerThread: pool-1-thread-2 End. Time = Mon May 13 20:42:57 CST 2019
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:57 CST 2019----------: 7
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:58 CST 2019----------: 8
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:42:59 CST 2019----------: 9
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:00 CST 2019----------: 10
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:01 CST 2019----------: 11
committerThread: pool-1-thread-2 Start. Time = Mon May 13 20:43:02 CST 2019
committerThread: pool-1-thread-2 End. Time = Mon May 13 20:43:05 CST 2019
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:05 CST 2019----------: 12
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:06 CST 2019----------: 13
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:07 CST 2019----------: 14
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:08 CST 2019----------: 15
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:09 CST 2019----------: 16
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:10 CST 2019----------: 17
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:11 CST 2019----------: 18
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:12 CST 2019----------: 19
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:13 CST 2019----------: 20
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:14 CST 2019----------: 21
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:15 CST 2019----------: 22
ChildJob processing at: pool-1-thread-1 : Mon May 13 20:43:16 CST 2019----------: 23