我不知道是否还有其他好的方法可以达到我想要的结果,谢谢。
我有一个要求,根据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。处理完地址后,我想唤醒下一个要执行的线程。
答案 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
方法(其中Worker
是obs.removeListener(this)
参数)中调用changed
来实现。 / li>