ThreadPoolExectutor 中的每个 submit() 调用仅调用一次 ThreadFactory newThread() 方法

ThreadFactory newThread() method called only once for each submit() call in ThreadPoolExectutor

我正在尝试为提交给 ThreadPoolExecutor 的每个 MyRunnable 分配一个编号,但我没有成功。

我的代码片段:

import java.util.concurrent.*;

class SimpleThreadFactory implements ThreadFactory {
   String name;
   static int threadNo = 0;

   public SimpleThreadFactory (String name){
       this.name = name;
   }
   public Thread newThread(Runnable r) {
     ++threadNo;
     System.out.println("thread no:"+threadNo);
     return new Thread(r,name+":"+threadNo );
   }
   public static void main(String args[]){
        SimpleThreadFactory factory = new SimpleThreadFactory("Ravindra");
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1,5,10,TimeUnit.SECONDS,new ArrayBlockingQueue(100),factory);
        for ( int i=0; i < 10; i++){
            executor.submit(new MyRunnable());
        }
        executor.shutdown();
    }
 }

 class MyRunnable implements Runnable {
     public void run(){
         System.out.println("Runnable:"+Thread.currentThread().getName());
     }
 }

我的期望:

executor.submit(new MyRunnable()); 应该在 ThreadFactory 中为执行器上的每个提交调用 newThread。但实际上,它只发生过一次。

输出:

thread no:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1
Runnable:Ravindra:1

为什么 submit() 不为每个提交的 Runnable 任务创建新线程?

如何为提交给执行程序的每个 MyRunnable 分配一个序列号?

提前致谢

其他答案解释了为什么线程不超过一个。我关于如何实现你真正想要的东西的建议是:

首先,计算 运行nable 的实例数,而不是 运行 所在的线程数:例如像这样 ->

class MyRunnable implements Runnable{
    private static long _mySequenceCounter = 0; // Maybe use an AtomicLong?
    private final long mySeqNo;

    MyRunnable(){ mySeqNo = ++_mySequenceCounter; }

// Your other stuff here

}

在 run-method 中,如果满足您的要求,您可以重命名当前线程。或者您可以只输出 运行nable id 并保留线程名称。这样做的好处是您会知道,哪个线程被重用于哪个任务……如果这对您有任何价值的话。

备注:以上片段只是为了说明如何满足您识别任务的要求。当然,如果您需要 thread-safety,您可以改进它(如果 MyRunnables 是在超过 1 个线程上创建的,则代码段可能会有问题)。

long 应该会给你相当多的序列号,但请注意,即使是 long 也会在某个时候翻转。因此,如果您的应用程序 运行 很长并且新 MyRunnable 的频率很高,您可能需要解决这个问题。

尝试为您的 "run" 方法添加休眠:这里的执行时间可能太短,不需要很多线程...

问题是 CorePoolSize 和队列之间的交互。

来自Javadoc

"If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread."

"If there are more than corePoolSize but less than maximumPoolSize threads running, a new thread will be created only if the queue is full."

所以目前,您的任务会排队直到 CorePoolSize 中有 space(即当您当前正在执行的任务完成时),因此您目前不会使用超过 1 个线程。

请参阅 ThreadPoolExecutor JavaDoc Core and maximum pool sizes

When a new task is submitted in method execute(java.lang.Runnable), .... If there are more than corePoolSize but less than maximumPoolSize threads running, a new thread will be created only if the queue is full.

为了让您的代码创建更多线程,我更改了这一点:

        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                // Core pool size
                5,
                // Max pool size
                5,
                // Resize time
                1,
                // Resize time units
                TimeUnit.MILLISECONDS,
                // Queue of runnables - I CHANGED THIS TO 10
                new ArrayBlockingQueue(10),
                // Factory to use for threads.
                factory);
        for (int i = 0; i < 100; i++) {
            executor.submit(new MyRunnable());
        }