代码之家  ›  专栏  ›  技术社区  ›  Maxim Veksler

ThreadLocal思考(或者:sun的javadoc错了吗?)

  •  5
  • Maxim Veksler  · 技术社区  · 15 年前

    我一直在阅读关于ThreadLocal的文章,试图了解它是如何工作的以及为什么我们需要它。

    到目前为止,我学到的是:

    1. ThreadLocal类允许在线程级别保存一个对象的实例
    2. 实例是通过重写initialValue()创建的
    3. each thread's HashMap
    4. 常识用法示例 can be found here

    一切似乎都很好,直到我试着从 javadoc ,代码如下:

     import java.util.concurrent.atomic.AtomicInteger;
    
     public class UniqueThreadIdGenerator {
    
         private static final AtomicInteger uniqueId = new AtomicInteger(0);
    
         private static final ThreadLocal < Integer > uniqueNum = 
             new ThreadLocal < Integer > () {
                 @Override protected Integer initialValue() {
                     return uniqueId.getAndIncrement();
             }
         };
    
         public static int getCurrentThreadId() {
             return uniqueId.get();
         }
     } // UniqueThreadIdGenerator
    

    如果我正确理解了这段代码,那么调用getCurrentThreadId()应该会返回正确的自动递增线程数,唉,它会为我返回0。总是0,不考虑我已经启动了多少线程。

    为了让它为我工作,我必须将getCurrentThreadId()改为

         public static int getCurrentThreadId() {
             return uniqueId.get();
         } 
    

    在这种情况下,我得到了正确的值。

    下面提供了我的代码,我遗漏了什么(不是javadoc真的错了,对吧??)

    package org.vekslers;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class UniqueThreadIdGenerator extends Thread {
    
        private static final AtomicInteger uniqueId = new AtomicInteger(0);
    
        private static final ThreadLocal <Integer> uniqueNum = 
            new ThreadLocal <Integer> () {
                @Override protected Integer initialValue() {
                    return uniqueId.getAndIncrement();
            }
        };
    
        public static int getCurrentThreadId() {
            return uniqueNum.get();
        }
    
    
    
    
        //////////////////////////////////////////////////
        // Testing code...
        //////////////////////////////////////////////////
        private static volatile boolean halt = false;
    
        public UniqueThreadIdGenerator(String threadName) {
            super(threadName);
        }
    
        @Override
        public void run() {
            System.out.println(Thread.currentThread() + " PREHALT " + getCurrentThreadId());
            while(!halt)
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                }
            System.out.println(Thread.currentThread() + " POSTHALT " + getCurrentThreadId());
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new UniqueThreadIdGenerator("t1");
            Thread t2 = new UniqueThreadIdGenerator("t2");
            Thread t3 = new UniqueThreadIdGenerator("t3");
            Thread t4 = new UniqueThreadIdGenerator("t4");
    
            t3.start();
            t1.start();
            t2.start();
            t4.start();
    
            TimeUnit.SECONDS.sleep(10);
            halt = true;
        }
    } // UniqueThreadIdGenerator
    

    输出:

    Thread[t3,5,main] PREHALT 0
    Thread[t1,5,main] PREHALT 1
    Thread[t2,5,main] PREHALT 2
    Thread[t4,5,main] PREHALT 3
    Thread[t4,5,main] POSTHALT 3
    Thread[t2,5,main] POSTHALT 2
    Thread[t1,5,main] POSTHALT 1
    Thread[t3,5,main] POSTHALT 0
    

    1 回复  |  直到 8 年前
        1
  •  9
  •   Stephen Denne    15 年前

    javadocs是错误的。
    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6475885

    Java 7's javadoc

     import java.util.concurrent.atomic.AtomicInteger;
    
     public class ThreadId {
         // Atomic integer containing the next thread ID to be assigned
         private static final AtomicInteger nextId = new AtomicInteger(0);
    
         // Thread local variable containing each thread's ID
         private static final ThreadLocal<Integer> threadId =
             new ThreadLocal<Integer>() {
                 @Override protected Integer initialValue() {
                     return nextId.getAndIncrement();
             }
         };
    
         // Returns the current thread's unique ID, assigning it if necessary
         public static int get() {
             return threadId.get();
         }
     }