我有一个方法,我使用ThreadPoolExecuter创建一些文件,然后压缩创建的文件。
private void createAndZip(){
// Some Code
ThreadPoolExecutor executer = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
for(String str : someStringList){
// This piece of code creates files and drops to certain location.
executer.execute(new MyRunnable());
}
executer.shutdown();
// Code to Zip the files created above.
}
现在我创建zip文件的代码甚至在创建所有文件之前就已运行,因此并非所有文件都被压缩。
请帮忙。我试过睡眠,但不能保证创建文件需要多长时间。
答案 0 :(得分:3)
您需要在执行程序对象上调用awaitTermination
,以便等待执行程序完成关闭。
答案 1 :(得分:1)
在您的代码块中,您缩小了Executors.newFixedThreadPool(5)
的回报范围。您有一个选择是使用它返回的ExecutorService
。该类已经具有避免必须重新实现同步代码(如锁存器)的功能。例如:
使用期货
private void createAndZip(ExecutorService executor) throws ExecutionException, InterruptedException {
// Some Code
List<String> list = new ArrayList<>();
// For a number of reasons ExecutorService should be constructed outside
// ExecutorService executer = Executors.newFixedThreadPool(5);
List<Future<?>> futures = new ArrayList<>();
for(String str : list){
// This piece of code creates files and drops to certain location.
futures.add(executer.submit(new MyRunnable()));
}
// async work
for (Future<?> future : futures) {
future.get(); // blocks
}
// Code to Zip the files created above.
}
这里有一些优点:
使用Java8 Lambda,可以以更紧凑的方式编写循环。
分叉/加入
也许更适合您的任务,特别是如果您要处理文件树是Fork/Join framework。在这里,您可以将处理和压缩转换为提交到fork-join池的任务集合。这很简洁,因为你可以获得整个zip文件的Future,允许你从主线程中生成整个zip。与使用fork / join的设计类似的东西可能是:
static class PrepareFile extends RecursiveTask<Void> {
private String filePath;
PrepareFile(String filePath) {
this.filePath = filePath;
}
@Override
protected Void compute() {
try {
System.out.println(filePath);
Thread.sleep(1009L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return null; // void
}
}
static class ZipTask extends RecursiveTask<String>
{
private List<String> files;
ZipTask(List<String> files) {
this.files = files;
}
@Override
protected String compute() {
List<PrepareFile> prepareTasks = new ArrayList<>();
for(String file : files) {
PrepareFile fileTask = new PrepareFile(file);
prepareTasks.add(fileTask);
fileTask.fork();
}
for(PrepareFile task : prepareTasks) {
task.join(); // can collect results here
}
System.out.println("Zipping");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Done task");
return "filename.zip";
}
}
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
List<String> toProcess = Arrays.asList("a","b");
String filename = pool.invoke(new ZipTask(toProcess));
System.out.println("Zipped " + filename);
}
这是一个你想要改变一些事情的例子,比如任务的返回类型以及如何调用任务。
在awaitTermination上
调用shutdown后可以使用awaitTermination
方法等待所有进程终止。然而,在长时间运行的服务或程序中,这可能不是那么理想,其中线程池可以在操作之间共享。
答案 2 :(得分:1)
我认为你可以在这里使用Future
个对象。而不是在执行程序上调用execute()
使用submit()
方法。这应该为您提交给执行者的每个任务提供一个Future
对象。提交完所有任务后,只需循环查看所获得的期货清单,并在每个期货上调用get()
。这是一个阻塞调用,它会一直等到相应的任务完成。
这样做的好处是,您可以检索从任务中抛出的任何异常,然后决定是否压缩文件。
请参阅此代码 -
private void createAndZip() throws Exception {
// Some Code
ThreadPoolExecutor executer = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
// collect all futures
List<Future> futures = new ArrayList<>();
for(String str : someStringList){
// This piece of code creates files and drops to certain location.
futures.add(executer.submit(new MyRunnable()));
}
// wait for all tasks to finish
try {
for (Future future : futures) {
future.get();
}
} catch (Exception e) {
e.printStackTrace();
if (e instanceof ExecutionException) {
throw e;
}
} finally {
executer.shutdown();
}
// Code to Zip the files created above.
}
答案 3 :(得分:0)
我使用CountDownLatch来解决问题。这是示例代码。
private void createAndZip() throws Exception{
CountDownLatch latch = new CountDownLatch(someStringList.size());
// Some Code
ThreadPoolExecutor executer = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
for(String str : someStringList){
// This piece of code creates files and drops to certain location.
executer.execute(new MyRunnable(latch));
}
executer.shutdown();
// Code to Zip the files created above.
try {
latch.await();
} catch (InterruptedException exception) {
throw new GIException(exception);
}
//Code here.
}
public class MyRunnable implements Runnable{
CountDownLatch latch = null;
MyRunnable(CountDownLatch latch){
this.latch = latch;
}
@Override
public void run() {
try {
// Some Logic
latch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
}