javafx多线程如何顺序执行?

时间:2019-06-22 16:13:59

标签: java multithreading javafx

我不知道是否还有其他好的方法可以达到我想要的结果,谢谢。

我有一个要求,根据URL,创建多个webview线程,并按顺序执行它们,例如线程执行,然后触发线程两次执行,依此类推,我使用了同步的(lobject)方法,但是JAVAfx遇到问题,代码如下:

public class LockObject {

    public int orderNum = 1;
    public final static int MaxValue=9;

    public LockObject(int orderNum){
        this.orderNum = orderNum;
    }
}


public class DownloadThread extends Thread{

    private LockObject lobject;
    private int printNum =0;
    private String url;

    public DownloadThread(LockObject lobject,int printNum,String url){
        this.lobject=lobject;
        this.printNum = printNum;
        this.url = url;
    }
    @Override
    public void run() {
        synchronized(lobject){
            while(lobject.orderNum <= lobject.MaxValue){
                if(lobject.orderNum == printNum){
                    System.out.print(printNum);
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            webView.getEngine().load(url);
                            webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
                                @Override
                                public void changed(ObservableValue<? extends Worker.State> observable, Worker.State oldValue, Worker.State newValue) {
                                    if (newValue == Worker.State.SUCCEEDED) {
                                        try {
                                            //xxxxx 

                                            // java.lang.IllegalMonitorStateException
                                            lobject.notifyAll();
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }
                            });
                        }
                    });
                    lobject.orderNum++;
                    if(lobject.orderNum==downloadThreads.length){
                        saveCsvFile(goodCSVS);
                    }
                    //lobject.notifyAll();  is ok
                }else{
                    try {
                        lobject.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}


通话地点


private DownloadThread[] downloadThreads;
LockObject lobject = new LockObject(1);
downloadThreads = new DownloadThread[tableView.getItems().size()];
for (int i = 0; i < tableView.getItems().size(); i++) {
    UrlModel item = tableView.getItems().get(i);
    downloadThreads[i] = new DownloadThread(lobject,tableView.getItems().size()-i,item.getLink());
    downloadThreads[i].start();
}

在Platform.runLater的run方法中调用lobject.notifyAll()将报告IllegalMonitorStateException。处理完地址后,我想唤醒下一个要执行的线程。

1 个答案:

答案 0 :(得分:2)

如果需要按顺序执行多个任务,则无需创建多个线程。仅使用一个线程将保证下一个任务仅在前一个任务完成后才执行。您还应该考虑使用CountDownLatch而不是在对象上进行同步。

ExecutorService executor = Executors.newSingleThreadExecutor();
try {
    for (UrlModel model : tableView.getItems()) {
        executor.submit(() -> {
            CountDownLatch latch = new CountDownLatch(1);
            Platform.runLater(() -> {
                engine.load(model.getLink())
                engine.getLoadWorker().runningProperty().addListener((obs, ov, nv) -> {
                    if (!nv) {
                        latch.countDown();
                    }
                });
            });
            latch.await();
            // do whatever needs to happen after the WebEngine finishes loading
            return null; // using #submit(Callable) and Callable needs to return something
        });
    }
} finally {
    executor.shutdown();
}

一些注意事项:

  • 如果表中没有要处理的项目,则可能要避免创建ExecutorService。也就是说,假设您不会每次都重复使用相同的ExecutorService
  • 如果您重复使用ExecutorService,请不要致电shutdown()
  • ExecutorService使用非守护线程。您可以通过提供创建后台驻留程序线程的ThreadFactory进行自定义。
  • 我在Worker#running属性而不是status属性中添加了一个侦听器,以确保无论负载的终端状态如何(例如,是否为{ {1}},countDown()SUCCEEDED)。
  • 您可能想要在完成后删除添加到CANCELLED属性中的侦听器。您可以通过使用匿名类(而不是我使用的lambda表达式)并在FAILED方法(其中Workerobs.removeListener(this)参数)中调用changed来实现。 / li>