项目中使用到了ThreadPoolExecutor,这个是挺好的东西,线程池的实现。但有一点不太爽的是,用Jprofiler调试由它创建的线程的时候,看到的都是pool-1-thread-1\2\3\4之类的。这是它自身的默认规则产生的,pool代表这是池,-1-代表是第几个ThreadPoolExecutor产生的,-thread-1是递增的。
所以每次我都要点 Thread Dumps 去查看线程执行的具体的代码与堆栈信息,推测是哪个地方出的问题。虽然说也能看出来,但很不直观嘛。于是有了一个想法,能不能不要用它的默认名称,由我自己的设定线程的名字,这样就一目了然了。把idea和master王说了,觉得也是个好主意。当然就只是在开发阶段有帮助,系统稳定上线后就没有用了。
Executors.defaultThreadFactory()是缺省的创建线程的实现。看下源码,
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
之所以在工具中看到所有的线程都是以 pool- 开头的,那是因为人家就是写死的。
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private 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;
}
}
我想要改成的格式是 pool-prjname-具体thread-1这种形式,如果说项目中所有代码共用一个pool,我可以直接把 poolNumber.getAndIncrement() 换成想要的名称。没错。但是具体thread呢?再搞一个参数,从上层传递进来替换吗?最开始发现貌似可以的。当然了,这意味着原生的Executors不能用了,把所有代码都copy到一个新类里,可能还会关联到其他类,也一并copy,如果不是关联到很多类的话,还是可以的。如果一层又一层,就比较没意思了。
使用方式:pool.taskPressIn(msgThread, "发送tmp"); 发送tmp就是我想要的具体thread的名称。但通过工具多次观察后,发现thread名称不是传进去的那个。认真考虑了newCachedThreadPool这个池,它是线程可复用的。当我提交了一个带名称的任务实例后,池子里其实是有空闲的线程的,这些线程可能就是之前命过名的,直接运行实例了,名称也就不会变了。
我最开始想着从池子中使用的线程入手,用的哪个就改哪个的名称,由于跟代码,想发现任务execute时,怎么获取线程的,master王想了一个办法。
我们说一个线程在start后才会执行run方法,run方法的执行表示这个task真正被线程运行了,这时线程的名称也就确定了。所以可以在run的第一句加上
Thread.currentThread().setName(ThreadPoolFairEx.renameThread(Thread.currentThread(), this.threadName));
Thread.currentThread()把当前的运行的线程传进去,renameThread()是一个替换string的方法而已,把自定义的threadName替之。然后currentThread再setName。这样就是这种效果