通过executor实现java线程重用

通过executor实现java线程重用,java,multithreading,threadpool,executorservice,executors,Java,Multithreading,Threadpool,Executorservice,Executors,我对以下几点感到困惑: 要在Java程序中使用线程,最简单的方法是扩展Thread类并实现runnable接口(或简单地实现runnable)。 开始线程的执行。我们必须调用线程的方法start(),它反过来调用线程的方法run()。于是线程开始了。 方法start()(除非我错了)必须准确调用,并且每个线程只能调用一次。因此,线程实例不能被重用,除非run方法本身在某种程度上运行在无限循环中,这有助于线程重用的自定义实现。 现在是javadoc 说 调用execute将重用以前构造的线程(如果

我对以下几点感到困惑:
要在Java程序中使用线程,最简单的方法是扩展Thread类并实现runnable接口(或简单地实现runnable)。
开始线程的执行。我们必须调用线程的方法start(),它反过来调用线程的方法run()。于是线程开始了。
方法start()(除非我错了)必须准确调用,并且每个线程只能调用一次。因此,线程实例不能被重用,除非run方法本身在某种程度上运行在无限循环中,这有助于线程重用的自定义实现。
现在是javadoc 说

调用execute将重用以前构造的线程(如果可用)

我不明白这是如何实施的。 我在executor方法的execute方法中提供我的自定义线程,例如

  ExecutorService myCachedPool = Executors.newCachedThreadPool();
  myCachedPool.execute(new Runnable(){public void run(){  
     //do something time consuming

  }});
如何重用我委托给executor框架的这个自定义线程?
当我们不能在程序中调用方法start()时,是否允许执行者调用方法start()超过1次? 我是不是误解了什么


谢谢。

请注意,调用
start()
的不是
Executor
——而是
ExecutorService
。不,它没有两次调用
start()
。它不会启动您直接使用
Thread.start()
给它的任务。。。相反,它启动一个线程,该线程知道该线程池的工作队列。线程基本上会等待,直到有一些工作要做,然后拿起它并执行它,然后再返回等待。因此,尽管线程执行多个任务,
thread.start()
只被调用一次

编辑:从评论判断,您对
可运行
(这是要执行的任务)和
线程
(这是执行任务的内容)之间的区别有点困惑

同一线程可以执行多个任务。对于一个不使用线程池的非常简单的例子,请考虑如下:

public class MultiRunnable implements Runnable
{
    private final List<Runnable> runnables;

    public MultiRunnable(List<Runnable> runnables)
    {
        this.runnables = runnables;
    }

    public void run()
    {
        for (Runnable runnable : runnables)
        {
             runnable.run();
        }
    }
}
public类MultiRunnable实现Runnable
{
私人最终名单;
公共多运行(列表可运行)
{
this.runnables=runnables;
}
公开募捐
{
for(Runnable-Runnable:runnables)
{
runnable.run();
}
}
}
(忽略从多个线程使用
列表
的潜在线程安全问题。)

您可以创建一大堆能够执行不同任务的
Runnable
任务,然后创建一个
MultiRunnable
来依次运行它们。将
MultiRunnable
的实例传递到
Thread
构造函数中,然后在启动线程时,它将执行每个原始可运行任务。这有用吗?

它不会多次调用start();相反,池中的线程永远不会完成,只是保持活动状态——等待。如果您想查看,可以下载源代码

线程池中的每个线程都可以简单地
wait()
等待执行器给它一个新的Runnable,但是线程自己的
run()
方法尚未完成。它只是等待一个新的Runnable被提供给执行器。

要多次“启动”线程,请创建一个Runnable。例如:

//NO
private class T extends Thread { //not necessary to implement runnable
    public void run(){
        //...
    }
}
void someMethod(){
    T a = new T();
    a.start();
    a.start(); //NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO
}
相反

//Yes
private class T implements Runnable {
    public void run(){
        //...
    }
}
void someMethod(){
    T a = new T();
    new Thread(a).start();
    new Thread(a).start(); //YES YES YES
}
也可以这样做:

void someMethod(){
    final Runnable r = new Runnable(){
        public void run(){
            //...
        }
    };
    new Thread(r).start();
    new Thread(r).start();
}
// r could also be a field of you class. 

那么您的意思是,在javadoc中,它说“以前构造的线程将被重用”,它不是指传递给execute的可运行线程,而是指executors框架的内部线程?那么我的Runnable将被线程池的同一个线程重新实例化?我明白你的意思了吗?你的Runnable不会被重新测试的。您的可运行实例将被提供给池中的一个线程。该线程有其自己的
run()
方法,该方法不会(不能)被Runnable的
run()
方法替换。线程的run()方法将调用
Runnable
run()
方法,然后在
Runnable.run()
完成后,线程将最终(必须做一些簿记)返回到
等待
ing。@Jon:对不起,我把你弄丢了。那么,框架的内部线程得到重用,而不是作为参数传递以执行的runnable?我委托给框架的线程每次都将被重新实例化,但由框架创建的内部线程的同一实例重新实例化?@user384706:Yes。你的runnable不是一个线程——它只是一个要执行的任务。你需要区分两者;他们很不一样。@Jon:非常感谢。我唯一不确定的是,使用Executors有什么好处;因为如果我的类实现runnable(对于任务)的实例化成本很高,那么它将不会被重用,框架的同一线程将继续使用任务的新实例。那么,我将从这个api中获得什么呢?除非概念是实现runnable的每个类都是最小的。@user384706创建线程的开销相对较大,对此您无能为力。相比之下,创建一个类的实例是非常便宜的(如果你让它变得昂贵,例如它在其构造函数中命中一个数据库/读取文件等,那么你可以重构它,不像线程那样你无法控制其开销)@nos:那么我的任务不应该扩展线程,而应该实现runnable?因为如果扩展线程,线程创建的“相对较大的开销”仍然存在。对吗?