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());
}
我正在尝试为提交给 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());
}