Java 在循环上创建线程

Java 在循环上创建线程,java,multithreading,Java,Multithreading,我是线程新手,所以我想了解在一个循环中创建一组线程时,幕后发生了什么,以及它的含义/更好的方法 下面是一个例子: for (Page page : book) { Thread t = new Thread(new Runnable() { public void run() { //http request to get page and put into concurrent data structure } });

我是线程新手,所以我想了解在一个循环中创建一组
线程时,幕后发生了什么,以及它的含义/更好的方法

下面是一个例子:

for (Page page : book) {
    Thread t = new Thread(new Runnable() {
        public void run() {
            //http request to get page and put into concurrent data structure
        }
    });
    t.start();
    threads.add(t);
}
//wait for threads

正如您可能看到的,在我目前的特定用例中,我正在通过HTTP请求的对象进行分页。我知道这里不一定需要线程,相反,我可以发出异步请求,但是如何(通过解释)改进它。

在您的示例中,您正在为书中的每个
页面
对象创建并启动一个新线程。如果系统中的页面比内核多得多,则此选项不可用

到目前为止,直接创建和启动线程并跟踪它们也有点低级

更好的解决方案是使用
ExecutorService
并创建一些线程,例如,接近系统上的内核数量(对于I/O绑定任务,您可能希望创建更多线程:您可以查看此答案下面的注释)

例如:

final ExecutorService e = 
    Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

for (Page page : book) {
    e.submit( new Runnable() {
              //http request to get page and put into concurrent data structure}
}
然后,您将等待
执行器服务
终止其作业

请注意,根据从中获取信息的服务器的不同,您可能需要故意添加延迟,以避免“重击”服务器太多


某些网站会告诉您查询它们的频率(例如,比特邮票比特币交换允许每秒查询一次),如果您不尊重延迟,则会禁止您的IP。其他人不会给你任何好处,如果他们检测到你的网速过快,他们会简单地禁止你的IP。

“如果你的系统上的页面比内核多得多,这将是无效的。”-你知道线程可能大部分时间都会被网络绑定和阻塞吗?是的,但我想了解如何更好地使用线程(正如我在帖子中所说,我更愿意用异步请求解决这个特定问题,但这让我思考如何更有效地管理java中的线程)。@Martin James:当然,但如果OP的书中有5000页,那么创建5000个线程就没有多大意义了“因为它们可能会被网络绑定”。使用ExecutorService和大小接近内核数的固定线程池是“良好做法”。生成无数线程不是。对答案进行了一点编辑。我认为他的观点(我也同意)是,如果你想让N核cpu保持忙碌(即最大化吞吐量)您希望总线程数T足够大,从统计上讲,运行的线程数接近N。如果有大量网络绑定线程花费大量时间被阻止,则需要使T>>N。@JVMATL:当然可以,但这里OP讨论的是从“图书服务器”获取“页面”“。我想这是一个独特的服务器。这与编写一个网络爬虫不同,它可以并行地从完全无关的站点获取网页。但是,当然,OP可能想要进行实验,并确定T>N,如果它能提供更好的吞吐量。。。