pthreadID 线程ID 复用证明

背景

pthread 库中有一个 pthread_self() 接口用来获取线程 ID,但是这个 ID并不是内核中那个线程 ID,pthread_t 到底是个什么样的数据结构呢?因为 POSIX 标准并没有限制 pthread_t 的数据类型,所以该类型取决于具体实现。对于 Linux 目前使用的 NPTL 实现而言,pthread_t 类型的线程 ID,本质上就是一个进程地址空间上的一个地址,而且 pthread_t 类型的线程 ID很有可能被复用。进程之间不会存在重复的线程 ID,而且不同线程之间也不会重复,在任意时刻都是全局唯一的值。

来源:在学习偏向锁的过程中,偏向锁是不能重新偏向的,为什么在各个线程中发现都是偏向到同一个线程?
上一个线程拿到锁之后,是偏向锁。现在一个新线程拿到锁之后,可能复用了上一个ID。JVM判断加锁的对象是可偏向的,进一步对比发现偏向的线程还是当前线程,所以偏向锁使用成功。实际上这是一个新线程了。其实这样加上偏向锁性能还好些,免得升级锁。

证明

JNI native code 获取线程ID

1
2
3
4
5
JNIEXPORT void JNICALL Java_jnitool_JniTool_getThreadID
(JNIEnv * env, jobject obj){
fprintf(stdout,"java_lock log PID = %d TID = %lu \n",getpid(),pthread_self());

}

测试代码,让线程顺序执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public static void main(String[] args) throws Exception {

out.println("\n main ------------------------ start");
JniTool jniTool = new JniTool();
Thread thread1 = new Thread(new Runnable() {
public void run() {
out.println("t1------------------------ start");
jniTool.getThreadID();
out.println("java getId "+(Thread.currentThread().getId()));
out.println("t1------------------------ end");
}
});

thread1.start();
thread1.join();

Thread thread2 = new Thread(new Runnable() {
public void run() {
out.println("t2------------------------start");
jniTool.getThreadID();
out.println("java getId "+(Thread.currentThread().getId()));
out.println("t2------------------------end");
}
});

thread2.start();
thread2.join();

Thread thread3 = new Thread(new Runnable() {
public void run() {
out.println("t3------------------------start");
jniTool.getThreadID();
out.println("java getId "+(Thread.currentThread().getId()));
out.println("t3------------------------end");
}
});

thread3.start();
thread3.join();
out.println("\n main ------------------------ end");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 main ------------------------ start
t1------------------------ start
java_lock log PID = 55 TID = 140073151424256
java getId 8
t1------------------------ end
t2------------------------start
java_lock log PID = 55 TID = 140073151424256
java getId 9
t2------------------------end
t3------------------------start
java_lock log PID = 55 TID = 140073151424256
java getId 10
t3------------------------end

main ------------------------ end

观察输出,查看线程ID 确实被复用了。