gpt4 book ai didi

java - 产生其他服务/任务的后台服务

转载 作者:行者123 更新时间:2023-12-01 11:02:15 25 4
gpt4 key购买 nike

我正在尝试了解 javafx 中的服务/任务以及如何处理将它们嵌套在一起。我的应用程序是一个简单的 RSS 下载器。它下载多个提要,并且还下载每个提要项目的 <link> 内的 html。 。我希望整个下载过程以及每个 rss feed 下载和每个 html 下载都是异步的(以防止 GUI 卡住)。我希望这个过程看起来像这样。

Application thread.
|
|
|--------Download process start(Service)
| |
| |
| |----RSS download start(Service)
| | |(30+ Tasks that each download an individual feed.
| |----RSS download end
| |
| |
| |----HTML download start(Service)
| | |(100+ Tasks that each download an individual HTML page.
| |----HTML download end
| |
| |
|--------Download process end.
|
|

我的代码。 downloadStart() 启动 Downloader服务。

    @Override 
public void downloadStart(List<Channel> channels) {
Downloader downloader = new Downloader(channels);
downloader.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent t) {
List<Article> result = (List<Article>)t.getSource().getValue();
display.printToOutput("Completed download process : " + result.size());
}
});
downloader.start();
}

Downloader类。

public class Downloader extends Service<List<Article>> {

List<Channel> channels;

public Downloader(List<Channel> channels){
this.channels = channels;
}

public void downloadRSS() {
for(Channel channel : channels){
RSSDownloadService<List<Article>> downloader = new RSSDownloadService<List<Article>>(channel);
downloader.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent t) {
List<Article> result = (List<Article>)t.getSource().getValue();
downloadHTML(result);
}
});
downloader.start();
}
}

private void downloadHTML(List<Article> articles){
HTMLDownloadService<List<Article>> downloader = new HTMLDownloadService<List<Article>>(articles);
downloader.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent t) {
List<Article> result = (List<Article>)t.getSource().getValue();
//how do i tell the Downloader service to return this result?
}
});
downloader.start();
}

@Override
protected Task<List<Article>> createTask() {
return new Task<List<Article>>() {
protected List<Article> call() {
downloadRSS();
//i can't return anything until downloadHTML() finishes!!
}
};
}

}

问题:启动Downloader服务后,显示createTask()方法调用downloadRSS()并期望一个返回值。然而,downloadRSS()方法不返回任何内容,它开始 RSSDownloadService 。当RSSDownloadService成功后,它会调用 downloadHTML(),该函数从 HTMLDownloadService 开始。最后,当成功时,我想结束整个 Downloader服务并返回 List的文章。我不知道如何继续。

RSSDownloadServiceHTMLDownloadService工作得很好。它们对我来说很容易实现,因为它们调用一个带有返回值的方法。然而 `DownloaderService' 不知何故需要等待 2 个服务完成,并返回第 2 个服务成功值。

最佳答案

如果我理解正确的话,你想要 downloadRSS()返回 List<Article>其中包含所有 Article HTMLDownloadService 返回的所有列表中的 s它会生成。

我认为以下内容可以满足您的要求:

public List<Article> downloadRSS() {

List<Article> mainList = Collections.synchronizedList(new ArrayList<>());
CountDownLatch latch = new CountDownLatch(channels.size());

for(Channel channel : channels){
RSSDownloadService<List<Article>> downloader = new RSSDownloadService<List<Article>>(channel);
downloader.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent t) {
List<Article> result = (List<Article>)t.getSource().getValue();
downloadHTML(result, mainList, latch);
}
});
downloader.setOnFailed(t -> {
// handle error if neccessary...
latch.countDown();
});
downloader.start();
}
latch.await();
// return a regular list, don't need the overhead of synchronization any more:
return new ArrayList<>(mainList);
}

private void downloadHTML(List<Article> articles, List<Article> mainList, CountDownLatch latch){
HTMLDownloadService<List<Article>> downloader = new HTMLDownloadService<List<Article>>(articles);
downloader.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent t) {
List<Article> result = (List<Article>)t.getSource().getValue();
mainList.addAll(result);
latch.countDown();
}
});

downloader.setOnFailed(t -> {
// handle error if needed...
latch.countDown();
});
downloader.start();
}

@Override
protected Task<List<Article>> createTask() {
return new Task<List<Article>>() {
protected List<Article> call() {
return downloadRSS();
}
};
}

这也许是一个更好的方法,使用 Java 8 流和内置并行化来管理大部分线程:

public class Downloader extends Task<List<Article>> {

private final List<Channel> channels ;

public Downloader(List<Channel> channels) {
this.channels = channels ;
}

@Override
public List<Article> call() throws Exception {
return channels.parallelStream()
.flatMap(channel -> getRssList(channel).parallelStream())
.flatMap(rss -> getHtmlList(rss).stream())
.collect(Collectors.toList());
}

private List<Article> getRssList(Channel channel) {
// this runs in its own thread, return List<Article> for given channel
}

private List<Article> getHtmlList(Article rss) {
// this runs in its own thread, return List<Article> for given rss
}
}

然后你在用户界面中所需要的就是:

List<Channel> channels = ... ;
Downloader downloader = new Downloader(channels);
downloader.setOnSucceeded(e -> {
List<Article> articles = downloader.getValue();
// update UI with articles...
});
Thread t = new Thread(downloader);
t.setDaemon(true) ; // will not prevent application exit...
t.start();

关于java - 产生其他服务/任务的后台服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33241860/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com