【问题标题】:Usage of parallelStream() resulting in unclosed Threads?使用 parallelStream() 导致未关闭的线程?
【发布时间】:2021-12-30 16:18:17
【问题描述】:

我正在编写一个 rss 媒体抓取器,而我的一个 parallelStream()s 导致线程未关闭。

都是Daemon Thread [ForkJoinPool.commonPool-worker-xx]线程。

我能发现的唯一区别是两个示例都是从不同的线程调用的。这可能是问题吗?即使当我尝试启动一个新的 Thread().start 时,parallelStream() 也将所有 ForkJoinPool 线程都留在后面。我还尝试使用像ArrayList<int> 这样的简单对象,结果相同。这是主线程之外的通缉行为吗?

或者只是文档中描述的行为(粗体部分):

ForkJoinPool 与其他类型的 ExecutorService 的主要区别在于 使用工作窃取的优点:池中的所有线程都试图 查找并执行提交到池和/或由其他人创建的任务 活动任务(如果不存在,则最终阻止等待工作)

public class MainRoutine {
    
    public static void startRoutine(SubReddit subReddit) {
        ArrayList<Entry> rssEntry = RSSgrab.pullRss(new SubReddit("pics", true, null));
        
        rssEntry.parallelStream().forEach(System.out::println); //produces unclosed threads
        System.out.println(Thread.currentThread().getName()); //prints AWT-EventQueue-0
    }

    public static void main(String[] args) {
        ArrayList<Entry> rssEntry = RSSgrab.pullRss(new SubReddit("pics", true, null));
        
        rssEntry.parallelStream().forEach(System.out::println); //this does not produce unclosed threads
        System.out.println(Thread.currentThread().getName()); //prints main
    //my bad, does also produce unclosed threads but the runtime is so short that I did not notice ofc
    }

}

入门类

public class Entry {
    String user;
    String userUri;
    String id;
    String uri;
    String date;
    String title;
    
    private ArrayList<String> media = new ArrayList<String>();
    
    public Entry(String user, String userUri, String id, String uri, String date, String title) {
        this.user = user;
        this.userUri = userUri;
        this.id = id;
        this.uri = uri;
        this.date = date;
        this.title = title;
    }

    @Override
    public String toString() {
        return "Entry [user=" + user + ", userUri=" + userUri + ", id=" + id + ", uri=" + uri + ", date=" + date
                + ", title=" + title + ", media="+getMedia().stream().map(s -> s+"; ").reduce("", String::concat)+"]";
    }

    public ArrayList<String> getMedia() {
        return media;
    }

    public void setMedia(ArrayList<String> media) {
        this.media = media;
    }
}

【问题讨论】:

  • 您为什么介意这些线程未关闭?公共池的要点是它一直在等待工作,并且由于它是一个守护线程,它不会阻止您的应用程序的关闭。
  • 因为我只接受了 6 个月的 java 培训并且仍然缺乏一些基础知识,这就是为什么我在做一些研究之后询问我是否不确定某些事情,谢谢我会记住它未来:)

标签: java multithreading java-stream


【解决方案1】:

基本上...您正在尝试解决一个不是问题的问题。常见的 fork-join 池是托管池。 JVM 会处理它。

如果这对你来说真的很重要,坏消息是你可能无能为力。公共池将忽略 shutdown()shutdownNow() 调用。这是设计使然。

有一个技巧可以让您创建自定义ForkJoinPool 并在其中运行您的流。见Custom thread pool in Java 8 parallel stream。完成后,您可以关闭池以使线程消失。

但是……这可能是个坏主意。重用现有池或公共池更有效。创建和销毁线程是昂贵的。重复执行此操作是因为您重复创建和销毁池是低效的。

常见的ForkJoinPool不应被视为线程泄漏。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-22
    • 2019-09-09
    • 2017-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    相关资源
    最近更新 更多