【发布时间】:2019-05-13 12:33:23
【问题描述】:
我想创建一个程序:
- 执行一项长时间运行的任务,比如说 ChildJob
- 暂停主要任务 ChildJob,并每隔几秒提交一次完成的工作
我想出了这段代码,它调度两个线程,每隔几秒提交一次(目前提交部分是一个 sop 语句),并且并行运行 ChildJob。
我面临的问题是,我无法正确同步两个线程。
- 在调用 commit() 时,ChildJob 线程继续处理。如何让 ChildJob 线程等待?
我知道使 process() 方法同步不是一种选择,因为在这种情况下,commit() 作业甚至不会运行。
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
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:32 IST 2019----------: 1
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:33 IST 2019----------: 2
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:34 IST 2019----------: 3
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----------: 4
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:36 IST 2019----------: 5
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:37 IST 2019----------: 6
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:38 IST 2019----------: 7
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:39 IST 2019----------: 8
committerThread: pool-1-thread-2 Start. Time = Mon May 13 17:51:40 IST 2019
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:40 IST 2019----------: 9
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:41 IST 2019----------: 10
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:43 IST 2019----------: 11
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----------: 12
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:45 IST 2019----------: 13
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:46 IST 2019----------: 14
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:47 IST 2019----------: 15
ChildJob processing at: pool-1-thread-1 : Mon May 13 17:51:48 IST 2019----------: 16
想要的结果:
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
【问题讨论】:
-
为什么要暂停线程并从另一个提交?您可以从 ChildJob 线程提交 - 更简单可靠。
-
因为,我需要根据时间使我的提交事件保持一致。说,每(n)秒。而且 ChildJob.process() 方法可以根据处理量放大或缩小,因此在代码中没有任何意义可以放置 commit() 代码。我正在尝试实现检查点/自动保存类型的功能。
标签: java multithreading thread-synchronization scheduledexecutorservice