ExecutorService의 이름 지정 스레드 및 스레드 풀
Executor
프레임 워크 를 활용하는 응용 프로그램이 있다고 가정 해 보겠습니다.
Executors.newSingleThreadExecutor().submit(new Runnable(){
@Override
public void run(){
// do stuff
}
}
이 응용 프로그램을 디버거에서 실행하면 다음과 같은 (기본) 이름으로 스레드가 생성됩니다 Thread[pool-1-thread-1]
. 보시다시피, 이것은별로 유용 Executor
하지 않으며 내가 알 수있는 한 프레임 워크는 작성된 스레드 또는 스레드 풀의 이름을 쉽게 지정할 수 있는 방법을 제공하지 않습니다.
그렇다면 스레드 / 스레드 풀의 이름을 어떻게 제공합니까? 예를 들어 Thread[FooPool-FooThread]
.
를 제공 할 ThreadFactory
수 newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
있습니다. 팩토리는 스레드 작성에 대한 책임이 있으며 이름을 지정할 수 있습니다.
Javadoc 을 인용하려면 :
새로운 스레드 만들기
를 사용하여 새 스레드가 생성됩니다
ThreadFactory
. 다르게 지정되지 않으면,Executors.defaultThreadFactory()
스레드가ThreadGroup
동일한NORM_PRIORITY
우선 순위 및 비 데몬 상태에 있도록 스레드를 작성 하는 a 가 사용됩니다 . 다른을 제공ThreadFactory
하면 스레드 이름, 스레드 그룹, 우선 순위, 데몬 상태 등을 변경할 수 있습니다.에서ThreadFactory
null을 반환하여 요청시 스레드를 작성하지 못하면newThread
실행 프로그램이 계속되지만 태스크를 실행할 수 없습니다.
구아바에는 거의 항상 필요한 것이 있습니다 .
ThreadFactory namedThreadFactory =
new ThreadFactoryBuilder().setNameFormat("my-sad-thread-%d").build()
그리고 당신에게 그것을 전달합니다 ExecutorService
.
고유 한 스레드 팩토리를 제공하여 적절한 이름의 스레드를 작성할 수 있습니다. 예를 들면 다음과 같습니다.
class YourThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
return new Thread(r, "Your name");
}
}
Executors.newSingleThreadExecutor(new YourThreadFactory()).submit(someRunnable);
스레드가 실행되는 동안 나중에 스레드 이름을 변경할 수도 있습니다.
Thread.currentThread().setName("FooName");
예를 들어 다른 유형의 작업에 동일한 ThreadFactory를 사용하는 경우 관심이 될 수 있습니다.
BasicThreadFactory
아파치 평민 - 랭에서 또한 명명 동작을 제공하는 데 유용합니다. 익명의 내부 클래스를 작성하는 대신 Builder를 사용하여 원하는대로 스레드 이름을 지정할 수 있습니다. 다음은 javadocs의 예입니다.
// Create a factory that produces daemon threads with a naming pattern and
// a priority
BasicThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern("workerthread-%d")
.daemon(true)
.priority(Thread.MAX_PRIORITY)
.build();
// Create an executor service for single-threaded execution
ExecutorService exec = Executors.newSingleThreadExecutor(factory);
Spring을 사용 CustomizableThreadFactory
하는 경우 스레드 이름 접두사를 설정할 수 있습니다.
예:
ExecutorService alphaExecutor =
Executors.newFixedThreadPool(10, new CustomizableThreadFactory("alpha-"));
Oracle에는이를 위한 공개 RFE 가 있습니다 . 오라클 직원의 의견으로는 문제를 이해하지 못하고 해결되지 않는 것 같습니다. JDK에서 지원하기가 간단하지만 (이전 버전과의 호환성을 유지하지 않고) RFE가 오해하는 것은 부끄러운 일입니다.
지적했듯이 자신의 ThreadFactory 를 구현해야합니다 . 이 목적으로 Guava 또는 Apache Commons를 가져 오지 않으려면 여기에 ThreadFactory
사용할 수 있는 구현을 제공하십시오 . 스레드 이름 접두어를 "pool"이외의 것으로 설정하는 기능을 제외하고는 JDK에서 얻는 것과 정확히 유사합니다.
package org.demo.concurrency;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* ThreadFactory with the ability to set the thread name prefix.
* This class is exactly similar to
* {@link java.util.concurrent.Executors#defaultThreadFactory()}
* from JDK8, except for the thread naming feature.
*
* <p>
* The factory creates threads that have names on the form
* <i>prefix-N-thread-M</i>, where <i>prefix</i>
* is a string provided in the constructor, <i>N</i> is the sequence number of
* this factory, and <i>M</i> is the sequence number of the thread created
* by this factory.
*/
public class ThreadFactoryWithNamePrefix implements ThreadFactory {
// Note: The source code for this class was based entirely on
// Executors.DefaultThreadFactory class from the JDK8 source.
// The only change made is the ability to configure the thread
// name prefix.
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
/**
* Creates a new ThreadFactory where threads are created with a name prefix
* of <code>prefix</code>.
*
* @param prefix Thread name prefix. Never use a value of "pool" as in that
* case you might as well have used
* {@link java.util.concurrent.Executors#defaultThreadFactory()}.
*/
public ThreadFactoryWithNamePrefix(String prefix) {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup()
: Thread.currentThread().getThreadGroup();
namePrefix = prefix + "-"
+ poolNumber.getAndIncrement()
+ "-thread-";
}
@Override
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;
}
}
당신이 그것을 사용하고 싶을 때, 당신은 모든 Executors
방법이 당신 자신을 제공 할 수 있다는 사실을 이용합니다 ThreadFactory
.
이
Executors.newSingleThreadExecutor();
쓰레드가 명명 된 곳에서 ExecutorService를 제공 pool-N-thread-M
하지만
Executors.newSingleThreadExecutor(new ThreadFactoryWithNamePrefix("primecalc"));
당신은 스레드의 이름을 지정하는 ExecutorService를 얻을 수 있습니다 primecalc-N-thread-M
. 짜잔!
private class TaskThreadFactory implements ThreadFactory
{
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "TASK_EXECUTION_THREAD");
return t;
}
}
ThreadFactory를 executorservice에 전달하면 좋습니다.
public interface ThreadFactory
요청시 새 스레드를 작성하는 오브젝트입니다. 스레드 팩토리를 사용하면 새 스레드에 대한 호출의 배선이 제거되어 응용 프로그램에서 특수 스레드 하위 클래스, 우선 순위 등을 사용할 수 있습니다.
Thread newThread(Runnable r)
새로운 Thread를 구축합니다. 구현은 우선 순위, 이름, 데몬 상태, ThreadGroup 등을 초기화 할 수도 있습니다.
샘플 코드 :
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.ThreadPoolExecutor.DiscardPolicy;
class SimpleThreadFactory implements ThreadFactory {
String name;
AtomicInteger threadNo = new AtomicInteger(0);
public SimpleThreadFactory (String name){
this.name = name;
}
public Thread newThread(Runnable r) {
String threadName = name+":"+threadNo.incrementAndGet();
System.out.println("threadName:"+threadName);
return new Thread(r,threadName );
}
public static void main(String args[]){
SimpleThreadFactory factory = new SimpleThreadFactory("Factory Thread");
ThreadPoolExecutor executor= new ThreadPoolExecutor(1,1,60,
TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(1),new ThreadPoolExecutor.DiscardPolicy());
final ExecutorService executorService = Executors.newFixedThreadPool(5,factory);
for ( int i=0; i < 100; i++){
executorService.submit(new Runnable(){
public void run(){
System.out.println("Thread Name in Runnable:"+Thread.currentThread().getName());
}
});
}
executorService.shutdown();
}
}
산출:
java SimpleThreadFactory
thread no:1
thread no:2
Thread Name in Runnable:Factory Thread:1
Thread Name in Runnable:Factory Thread:2
thread no:3
thread no:4
Thread Name in Runnable:Factory Thread:3
Thread Name in Runnable:Factory Thread:4
thread no:5
Thread Name in Runnable:Factory Thread:5
....기타
빠르고 더러운 방법은 방법에 사용 Thread.currentThread().setName(myName);
하는 run()
것입니다.
Executors.newSingleThreadExecutor(r -> new Thread(r, "someName")).submit(getJob());
Runnable getJob() {
return () -> {
// your job
};
}
예를 들어 defaultThreadFactory와 같은 일부 기존 구현을 사용하여 고유 한 ThreadFactory 구현을 작성하고 끝에 이름을 변경할 수 있습니다.
ThreadFactory를 구현하는 예 :
class ThreadFactoryWithCustomName implements ThreadFactory {
private final ThreadFactory threadFactory;
private final String name;
public ThreadFactoryWithCustomName(final ThreadFactory threadFactory, final String name) {
this.threadFactory = threadFactory;
this.name = name;
}
@Override
public Thread newThread(final Runnable r) {
final Thread thread = threadFactory.newThread(r);
thread.setName(name);
return thread;
}
}
그리고 사용법 :
Executors.newSingleThreadExecutor(new ThreadFactoryWithCustomName(
Executors.defaultThreadFactory(),
"customName")
);
아래처럼 똑같이 사용합니다 ( guava
라이브러리 필요 ).
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("SO-POOL-%d").build();
ExecutorService executorService = Executors.newFixedThreadPool(5,namedThreadFactory);
This is my customized factory providing a customized names for thread dump analyzers. Usually I just give tf=null
to reuse JVM default thread factory. This website has more advanced thread factory.
public class SimpleThreadFactory implements ThreadFactory {
private ThreadFactory tf;
private String nameSuffix;
public SimpleThreadFactory (ThreadFactory tf, String nameSuffix) {
this.tf = tf!=null ? tf : Executors.defaultThreadFactory();
this.nameSuffix = nameSuffix;
}
@Override public Thread newThread(Runnable task) {
// default "pool-1-thread-1" to "pool-1-thread-1-myapp-MagicTask"
Thread thread=tf.newThread(task);
thread.setName(thread.getName()+"-"+nameSuffix);
return thread;
}
}
- - - - -
ExecutorService es = Executors.newFixedThreadPool(4, new SimpleThreadFactory(null, "myapp-MagicTask") );
For your convenience this is a thread dump loop for debug purpose.
ThreadMXBean mxBean=ManagementFactory.getThreadMXBean();
long[] tids = mxBean.getAllThreadIds();
System.out.println("------------");
System.out.println("ThreadCount="+tids.length);
for(long tid : tids) {
ThreadInfo mxInfo=mxBean.getThreadInfo(tid);
if (mxInfo==null) {
System.out.printf("%d %s\n", tid, "Thread not found");
} else {
System.out.printf("%d %s, state=%s, suspended=%d, lockowner=%d %s\n"
, mxInfo.getThreadId(), mxInfo.getThreadName()
, mxInfo.getThreadState().toString()
, mxInfo.isSuspended()?1:0
, mxInfo.getLockOwnerId(), mxInfo.getLockOwnerName()
);
}
}
The home-grown core Java solution that I use to decorate existing factories:
public class ThreadFactoryNameDecorator implements ThreadFactory {
private final ThreadFactory defaultThreadFactory;
private final String suffix;
public ThreadFactoryNameDecorator(String suffix) {
this(Executors.defaultThreadFactory(), suffix);
}
public ThreadFactoryNameDecorator(ThreadFactory threadFactory, String suffix) {
this.defaultThreadFactory = threadFactory;
this.suffix = suffix;
}
@Override
public Thread newThread(Runnable task) {
Thread thread = defaultThreadFactory.newThread(task);
thread.setName(thread.getName() + "-" + suffix);
return thread;
}
}
In action:
Executors.newSingleThreadExecutor(new ThreadFactoryNameDecorator("foo"));
I find it easiest to use a lambda as a thread factory if you just want to change the name for a single thread executor.
Executors.newSingleThreadExecutor(runnable -> new Thread(runnable, "Your name"));
As other answers already said, you may create and use your own implementation of the java.util.concurrent.ThreadFactory interface (no external libraries required). I am pasting my code below because it is different than previous answers since it uses String.format method and takes a base name for the threads as a constructor argument:
import java.util.concurrent.ThreadFactory;
public class NameableThreadFactory implements ThreadFactory{
private int threadsNum;
private final String namePattern;
public NameableThreadFactory(String baseName){
namePattern = baseName + "-%d";
}
@Override
public Thread newThread(Runnable runnable){
threadsNum++;
return new Thread(runnable, String.format(namePattern, threadsNum));
}
}
And this is an example of usage:
ThreadFactory threadFactory = new NameableThreadFactory("listenerThread");
final ExecutorService executorService = Executors.newFixedThreadPool(5, threadFactory);
참고URL : https://stackoverflow.com/questions/6113746/naming-threads-and-thread-pools-of-executorservice
'Programming' 카테고리의 다른 글
Jackson 열거 형 직렬화 및 DeSerializer (0) | 2020.05.07 |
---|---|
node_modules를 삭제하는 방법-Windows에서 깊은 중첩 폴더 (0) | 2020.05.07 |
ADB 쉘 입력 이벤트 (0) | 2020.05.07 |
프로그래밍 방식으로 EditText의 inputType을 설정 하시겠습니까? (0) | 2020.05.07 |
요청 실패 : 허용되지 않는 콘텐츠 유형 : AFNetworking 2.0을 사용하는 text / html (0) | 2020.05.07 |