背景

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. JNIEXPORT void JNICALL Java_jnitool_JniTool_getThreadID
  2. (JNIEnv * env, jobject obj){
  3. fprintf(stdout,"java_lock log PID = %d TID = %lu \n",getpid(),pthread_self());
  4. }

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

  1. public static void main(String[] args) throws Exception {
  2. out.println("\n main ------------------------ start");
  3. JniTool jniTool = new JniTool();
  4. Thread thread1 = new Thread(new Runnable() {
  5. public void run() {
  6. out.println("t1------------------------ start");
  7. jniTool.getThreadID();
  8. out.println("java getId "+(Thread.currentThread().getId()));
  9. out.println("t1------------------------ end");
  10. }
  11. });
  12. thread1.start();
  13. thread1.join();
  14. Thread thread2 = new Thread(new Runnable() {
  15. public void run() {
  16. out.println("t2------------------------start");
  17. jniTool.getThreadID();
  18. out.println("java getId "+(Thread.currentThread().getId()));
  19. out.println("t2------------------------end");
  20. }
  21. });
  22. thread2.start();
  23. thread2.join();
  24. Thread thread3 = new Thread(new Runnable() {
  25. public void run() {
  26. out.println("t3------------------------start");
  27. jniTool.getThreadID();
  28. out.println("java getId "+(Thread.currentThread().getId()));
  29. out.println("t3------------------------end");
  30. }
  31. });
  32. thread3.start();
  33. thread3.join();
  34. out.println("\n main ------------------------ end");
  35. }
  36. }
  1. main ------------------------ start
  2. t1------------------------ start
  3. java_lock log PID = 55 TID = 140073151424256
  4. java getId 8
  5. t1------------------------ end
  6. t2------------------------start
  7. java_lock log PID = 55 TID = 140073151424256
  8. java getId 9
  9. t2------------------------end
  10. t3------------------------start
  11. java_lock log PID = 55 TID = 140073151424256
  12. java getId 10
  13. t3------------------------end
  14. main ------------------------ end

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