前几天遇到一个关于java线程的疑惑,一直没有得到解答,甚至最后我认为这应该算是jdk的一个BUG,于是自不量力的提交了一个BUG到oracle官方,至今没有任何回复呢。
背景:
我做了一个定时下载某个网站图片的应用服务。
当时的想法很简单,因为每隔5分钟下载一次,一次可能需要下载多张,每个图片开一个线程去下载,并行下载完毕后线程就自动关闭了。5分钟后再开新的线程去下载,如此一直运行.......
问题:
按照上面的方法可以实现所有功能,但是在日志里发现一个很奇怪的问题,就是线程ID一直增加,没有减少,查阅了一下API里关于Thread的解释,里面是这样说的:
public long getId()
返回该线程的标识符。线程 ID 是一个正的 long 数,在创建该线程时生成。
线程 ID 是唯一的,并终生不变。
线程终止时,该线程 ID 可以被重新使用。
也就是说,线程Id应该是可以被回收的,一直增加是有问题的。
我尝试了好多方法验证,最终发现Id还是没有被重复利用,于是对API产生了一些怀疑,到官方在线查看英文的API是这样说的:
public long getId()
Returns the identifier of this Thread. The thread ID is a positive long number generated when this thread was created. The thread ID is unique and remains unchanged during its lifetime.
When a thread is terminated, this thread ID may be reused.
英文原版API的说法是 this thread ID may be reused. 我英语水平不是很好,may be确实可以翻译成“可以”,但是貌似不是很确定,人家的意思可能是:有可能被重复利用,也有可能不被重复利用。
我想这也是为什么提交bug到oracle没人理我的原因吧。
接下来看看jdk里关于Thread的实现(1.6版本):
访问上面的连接 查找线程id的定义: private long tid;
接着 查找 tid 的初始化 : tid = nextThreadID();
接下来查看初始化方法nextThreadID() 的实现:
private static synchronized long nextThreadID() {
return ++threadSeqNumber;
}
我们看到这里返回的Id只有增加,没有任何其他处理。
我们可以继续搜索对于 threadSeqNumber 的处理,看看是否有回收的处理:
最终发现只有一处定义,其他地方在没有处理 private static long threadSeqNumber;
至此,我明白为什么Thread的id只增加不减少了,但是我认为这个是不合理的,也是与API不符的,所以我斗胆提交了一个bug到oracle,至今无回应,哎。
本人做开发时间不久,被这个问题困扰很久,写出来希望得到大家的帮助。