暂停并恢复ExecutorService或关闭并重新启动Java Executor服务

时间:2013-10-05 11:55:07

标签: java javafx executorservice java.util.concurrent threadpoolexecutor

我正在开发一个javaFX项目,用户只需浏览几个文件,创建一个队列,点击开始上传,然后在指定路径上上传这些文件。现在,当用户单击暂停按钮时,必须暂停上载过程,当单击“恢复”时,必须从暂停的位置再次启动该过程。 所以,到现在为止,我已经通过Executors.newSingleThreadExecutor()创建了一个对象(文件)队列。并提交了任务。 在我的情况下,taks类被称为Item。 现在,当用户点击暂停按钮时,我调用executorService的shutdownnow()方法。 当用户点击resume时,我创建了一个全新的Executorservice实例。 但是,当我通过executor.execute方法提交作业时,它会跳过当前任务并恢复下一个任务,依此类推。 所以,我需要它从它最后执行的任务开始。 这是代码。

public class UploadManagerController implements Initializable {

private static boolean checkRunning = true;

private static String currentClient;
private static int currentView = 0;
private static int checkLastSelectedQueue = 0;
private static Timeline fiveSecondsWonder;
private List<File> uploadDir;
private static long currentSelectedRow = -1;
private static ThreadFactory threadFactory;
private static ExecutorService executor;
private static Thread t;
private static LinkedHashMap<String, ObservableList> clientUploadInfo;
private static HashMap<String, Long> clientUploadInfoCount;
private static HashMap<String, String> clientUploadInfoTotalSize;
private static HashMap<String, Double> clientUploadInfoTotalSizeLong;


  public static class Item extends Task<Void> {

    public SimpleStringProperty fileName = new SimpleStringProperty();
    public SimpleStringProperty fileSize = new SimpleStringProperty();
    public SimpleStringProperty ETA = new SimpleStringProperty();
    public SimpleStringProperty speed = new SimpleStringProperty();
    public SimpleStringProperty status = new SimpleStringProperty();
    public SimpleDoubleProperty progress = new SimpleDoubleProperty();
    public SimpleObjectProperty clientName = new SimpleObjectProperty();
    public SimpleStringProperty path = new SimpleStringProperty();
    public SimpleLongProperty id = new SimpleLongProperty();
    public File file;
    public long time = 0;

    // Getter and setter of above variables

    @Override
    protected Void call() throws Exception {
        File filee = this.getFile();
        FileInputStream is = new FileInputStream(filee); 
        String mRecordingFile = "UserSpecifiedPath\\" + this.getFileName();

        File fl = new File(mRecordingFile);
        if (fl.exists() && (this.getStatus().equals("error") != true || this.getStatus().equalsIgnoreCase("stopped") != true)) {
            fl.renameTo(new File("UserSpecifiedPath\\" + Util.getTime() + "_" + fl.getName()));

        }

        boolean checkDelete = false;
        for (String key : clientUploadInfo.keySet()) {
            if (clientUploadInfo.get(key).contains(this)) {
                checkDelete = true;
                break;
            }
        }
        if ( checkDelete) {
            java.nio.channels.FileChannel fc = is.getChannel();
            long totalSize = filee.length();
            long total = totalSize / 10000;
            java.nio.ByteBuffer bb = java.nio.ByteBuffer.allocate(10000);

            byte[] bytes;

            while (fc.read(bb) > 0) {

                bb.flip();
                bytes = bb.array();
                File f = new File(mRecordingFile);
                try (FileOutputStream fOut = new FileOutputStream(mRecordingFile, true)) {
                    fOut.write(bytes);
                }
                      bb.clear();
            }
        }


        return null;
    }
}

 @Override
public void initialize(URL url, ResourceBundle rb) {
    clientUploadInfo = new LinkedHashMap<>();
          threadFactory = new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {

            t = new Thread(r);
            try {
                t.join();
            } catch (InterruptedException ex) {
                System.out.println("inte");
            }
            t.setDaemon(true);
            return t;
        }
    };
    executor = Executors.newSingleThreadExecutor(threadFactory);
}

  @FXML
private void startupload(ActionEvent event) {
    ObservableList<Item> temp = FXCollections.observableArrayList();
    temp.addAll(clientUploadInfo.get(currentClient));
    currentView = 1;
    checkRunning = true;
    if (executor.isShutdown()) {
        executor = null;
        t=null;
        threadFactory = null;
        threadFactory = new ThreadFactory() {

            @Override
            public Thread newThread(Runnable r) {
                 t = new Thread(r);
                try {
                    t.join();
                } catch (InterruptedException ex) {
                    Logger.getLogger(UploadManagerController.class.getName()).log(Level.SEVERE, null, ex);
                }

                t.setDaemon(true);
                return t;
            }
        };
        executor = Executors.newSingleThreadExecutor(threadFactory);


         for (Item itm : temp) {
            if (itm.getStatus().equalsIgnoreCase("In Active") || itm.getStatus().equalsIgnoreCase("queued") || itm.getStatus().equalsIgnoreCase("error") || itm.getStatus().equalsIgnoreCase("stopped")) {

                executor.submit(itm);
            }
        }

    } else {
        for (Item itm : temp) {
            if (itm.getStatus().equalsIgnoreCase("In Active") || itm.getStatus().equalsIgnoreCase("queued") || itm.getStatus().equalsIgnoreCase("error") || itm.getStatus().equalsIgnoreCase("stopped")) {

                executor.execute(itm);
            }
        }
    }
}

@FXML
private void stopUpload(ActionEvent event) {
    checkRunning = false;
    executor.shutdownNow();

}
}

对不起我的英语,但让我试着解释一下, 在上面的代码中,它们有两个方法STARTUPLOAD和STOPUPLOAD,这两个方法在点击javafx按钮时被调用, 所以当我第一次点击startupload按钮时,它开始在clientUploadInfo.get(KEY)hasMap中上传文件,我在点击添加文件按钮时保持这个,我没有提到使代码缩短的代码,Item类包含所有细节。 点击停止上传按钮,调用stopUpload方法,再次点击开始上传按钮,调用startUpload方法但是要恢复上传过程,记得在我的情况下恢复上传,但是从下一个项目开始,它会保留当前项目就像点击停止按钮时一样。 任何帮助,将不胜感激 。 提前谢谢。

2 个答案:

答案 0 :(得分:2)

您的要求是可以停止任务。我认为通过暂停(但是你这样做)执行程序来实现这一点并不是一个好主意,因为暂停执行程序通常会非常不安全(有关详细信息,请参阅Thread.suspend()的javadoc),这是可能为什么执行者不支持这一点。

更好的设计是让任务在不应该继续的情况下等待,例如:

private boolean suspended;

synchronized void suspend() {
    suspended = true;
}

synchronized void resume() {
    suspended = false;
    notifyAll();
}

synchronized void waitWhileSuspended() {
    while (suspended) {
        wait();
    }
}

任务可以在可以安全中断的情况下定期调用waitWhileSuspended()

答案 1 :(得分:0)

尝试覆盖任务&lt;?&gt;要从同一个线程暂停和重启,你需要使用执行器和ThreadFactory获取线程的实例, 重新执行您的执行程序将始终跳过当前线程,因为它仍然在内存中并且具有指向它的链接,即使您放置了null。 所以,我建议你尝试暂停一旦完成当前线程,显示弹出窗口而不是向用户传递当前进程无法取消的消息,或者尝试覆盖你的Task和ThreadFactory并获取当前线程的ID并重新初始化那个线程。