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

发布于 2024-09-06 20:04:01 字数 3544 浏览 10 评论 0原文

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

到目前为止,我已经能够学到以下内容:

  1. ThreadLocal 类允许在线程级别保存对象的 1 个实例
  2. 该实例是通过重写initialValue() 创建的
  3. 该实例实际上存储在 每个线程的 HashMap
  4. 常识性使用示例 可以在这里找到

一切看起来都很好,直到我尝试从 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() 更改为 read

     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

ps 代码评论 OT或切中要点欢迎评论。

I've been reading about ThreadLocal, trying to understand how it works and why we need it.

So far what I've been able to learn is the following:

  1. ThreadLocal class allows to hold 1 instance of an object at the thread level
  2. The instance is created by overriding initialValue()
  3. The instance is actually stored in the each thread's HashMap
  4. A common sense usage example can be found here

All seemed fine, until I tried to run the example from the javadoc, the code is provided as following:

 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

If I understand this code correctly, calling getCurrentThreadId() should return the correct auto incremented thread number, alas it returns 0 for me. ALWAYS 0, without consideration of how many threads I have started.

To get this working for me I had to change getCurrentThreadId() to read

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

In which case I am getting correct values.

My code is provided below, what am I missing? (It's not that the javadoc is actually wrong, right??)

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

Output:

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

p.s. Code comments OT or to the point are welcome in comments.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

治碍 2024-09-13 20:04:01

javadoc 是错误的。
https://bugs.java.com/bugdatabase/view_bug?bug_id=6475885

Java 7 的 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();
     }
 }

The javadocs are wrong.
https://bugs.java.com/bugdatabase/view_bug?bug_id=6475885

Java 7's javadoc includes

 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();
     }
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文