问题
I am executing a Callable Object using ExecutorService thread pool. I want to give a name to this thread.
To be more specific, in older version I did this -
Thread thread = new Thread(runnable Task);
thread.setName("My Thread Name");
I use thread name in log4j logging, this helps a lot while troubleshooting. Now I am migrating my code from Java 1.4 to Java 1.6. I have written this(Given below)- but I dont know how to give name to this thread.
private final ExecutorService executorPool = Executors.newCachedThreadPool();
Future<String> result = executorPool.submit(callable Task);
Please give me some idea to give name to this thread?
回答1:
You may use the overloaded method:
java.util.concurrent.Executors.newCachedThreadPool(ThreadFactory)
which allows you to pass a
java.util.concurrent.ThreadFactory
that should allow you to set the thread's names via java.util.concurrent.ThreadFactory.newThread(Runnable)
:
Constructs a new
Thread
. Implementations may also initialize priority, name, daemon status,ThreadGroup
, etc.
Have a look at java.util.concurrent.Executors.DefaultThreadFactory
for a default implementation.
Addendum
Since I see that this thread is still visited, Guava (if you have it available) provides a ThreadFactoryBuilder that leverages the need of having an inner anonymous class and even allows for customizing parametrized names for your threads.
回答2:
I'm currently doing it somewhat like this:
someExecutor.execute(new Runnable() {
@Override public void run() {
final String orgName = Thread.currentThread().getName();
Thread.currentThread().setName(orgName + " - My custom name here");
try {
myAction();
} finally {
Thread.currentThread().setName(orgName);
}
}
});
回答3:
/**
* The default thread factory
*/
static class DefaultThreadFactory implements ThreadFactory {
static final AtomicInteger poolNumber = new AtomicInteger(1);
final ThreadGroup group;
final AtomicInteger threadNumber = new AtomicInteger(1);
final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null)? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
This is the original implementation in Java 1.5.0. So, you actually have the names as pool-x-thread where x stands for the order of the thread in the current thread group.
回答4:
You should be careful when renaming threads when your threads are managed by a thread-pool because they are actually being reused over and over again for different tasks and once renamed, you might find that the thread names in your logs don't make any sense... In order to avoid that unwanted behavior you should make sure that once your Runnable/Callable finished the thread name is restored.
One way to implement this is by wrapping every Runnable/Callable that is executed by the thread-pool with a decorator which handles all of the needed clean-ups.
回答5:
If you are using Spring, you may use org.springframework.scheduling.concurrent.CustomizableThreadFactory for that:
ExecutorService executorService = Executors.newCachedThreadPool(
new CustomizableThreadFactory("MyThreadNamePrefix"));
回答6:
I just had to do what you are asking for -- providing names to my thread groups -- so thanks to Andeas's answer, I created my own ThreadFactory as an inner-class to the class that is going to use it by copying Executors$DefaultThreadFactory, changing 3 lines by adding the parameter "groupname" to the constructor.
/**
* A thread factory that names each thread with the provided group name.
* <p>
* Except lines with "elarson modified", copied from code
* Executors$DefaultThreadFactory -- Doug Lea, Copyright Oracle, et al.
*/
static class GroupNameThreadFactory implements ThreadFactory {
private String groupname; /* elarson modified */
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
GroupNameThreadFactory(String groupname) {
this.groupname = groupname; /* elarson modified */
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
this.groupname + /* elarson modified */
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
Creating a ThreadPool from it is done as follows.
ThreadFactory threadfactory = new GroupNameThreadFactory("Monitor");
executor = Executors.newFixedThreadPool(NUM_THREADS, threadfactory);
Thanks user381878 for asking the question, and Andreas for the answer.
回答7:
Just create an anonymous ThreadFactory for getting the Executor Service. The ThreadFactory can supply the name for the thread as follows: "Thread A" or "Thread B" (see the example).
Then call the callable task using the different executor services:
Example Class:
public class ThreadTester {
public static void main(String[] args) {
ThreadTester threadTester = new ThreadTester();
threadTester.test();
}
private void test() {
ExecutorService executorservice = Executors.newCachedThreadPool(new ThreadFactory() {
@Override
public Thread newThread(Runnable arg0) {
return new Thread(arg0,"Thread A");
}
});
CallableTask taskA = new CallableTask();
executorservice.submit(taskA);
executorservice = Executors.newCachedThreadPool(new ThreadFactory() {
@Override
public Thread newThread(Runnable arg0) {
return new Thread(arg0,"Thread B");
}
});
CallableTask taskB = new CallableTask();
executorservice.submit(taskB);
}
}
Callable Task :
public class CallableTask implements Callable {
@Override
public Integer call() throws Exception {
int sum = 0;
for(int count=1;count<=30;count++){
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " Count :"+count);
sum = sum + count;
}
System.out.println(Thread.currentThread().getName() + " Sum :"+sum);
return sum;
}
}
回答8:
One approach that I've used, and in my case I had a number of futures fetching data in parallel controlled by a single class. I submit a number of jobs and get the futures back. I store the future in a map with the value as the job name. Then later on, when I'm doing a get with a timeout on all futures I have the name of the job from the map. It's not maybe the most flexible way but worked in my situation.
来源:https://stackoverflow.com/questions/3227040/how-to-give-name-to-a-callable-thread