2 zhuzhu923 zhuzhu923 于 2016.01.19 20:31 提问

Java中线程的问题:明明是同一个thread对象,但是threadLocal不是同一个

package hub;
/*为啥不同线程中的ThreadLocal是互相独立的。 明明是同一个thread对象

  • 打印出来的结果 在主线程里面是var2 ,在thread线程中是var1
    */
    public class ThreadLocalUsage extends Thread {
    public User user = new User();

    public User getUser() {
    return user;
    }

    @Override
    public void run() {
    this.user.set("var1");

    while (true) {
        try {
            sleep(1000);
        } catch (InterruptedException e) {
        }
        System.out.println(this.user.get());
    }
    

    }

    public static void main(String[] args) {

    ThreadLocalUsage thread = new ThreadLocalUsage();
    thread.start();
    
    try {
        sleep(4000);
    } catch (InterruptedException e) {
    }
    
    thread.user.set("var2");
    System.out.println(thread.user.get());
    

    }
    }

class User {

private static ThreadLocal<Object> enclosure = new ThreadLocal<Object>(); // is it must be static?

public void set(Object object) {
    enclosure.set(object);
}

public Object get() {
    return enclosure.get();
}

}

上面这个代码明明是一个thread对象,怎么打印出来的threadlocal的值不一样,也就是代表不是同一个threadlocal

3个回答

wojiushiwo945you
wojiushiwo945you   Ds   Rxr 2016.01.19 21:20

ThreadLocal对象本质类似一个以线程对象为key的哈希表,它能使线程中的某个值与保存值的线程对象关联起来。
所以上述你是两个线程中分别调用了同一个ThreadLocal对象的set方法,所以get方法返回的是当前线程set的值。各个线程中的get的值对应其set的值,所以结果是:

 Thread-0:var1
main:var2
Thread-0:var1

两个线程取到的get值各是各的,当然是两个值了。

wojiushiwo945you
wojiushiwo945you   Ds   Rxr 2016.01.19 20:55

你理解错了,不是同一个thread对象,而是同一个ThreadLocal enclosure对象,即thread.user.enclosure对象。
你是两个线程中分别set到ThreadLocal对象的key是某个线程,值是线程设置的值。
你可以打印当前线程+线程设置的值,可以看到你的代码中有两个线程对象main和ThreadLocalUsage两个线程,它们存储在同一个ThreadLocal变量中。修正测试代码如下:

    public void run() {
        this.user.set("var1");
        while (true) {
            try {
                sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println(Thread.currentThread().getName()+":"+this.user.get());
        }

    }

    public static void main(String[] args) {
        ThreadLocalUsage thread = new ThreadLocalUsage();
        thread.start();

        try {
            sleep(4000);
        } catch (InterruptedException e) {
        }

        thread.user.set("var2");
        System.out.println(Thread.currentThread().getName()+":"+thread.user.get());

    }

测试就可以看到这是两个不同线程的值。

wojiushiwo945you
wojiushiwo945you 回复zhuzhu923: 在ThreadLocalUsage线程中的user.set("var1")是以当前线程对象为key的。get操作是取到对应线程set操作的值的。这也是ThreadLocal类的意义,就是保证每个线程都只set/get自己的数据。
接近 2 年之前 回复
wojiushiwo945you
wojiushiwo945you 回复毕小宝: 你此处的thread.user是取到了ThreadLocal对象,然后set操作就是以当前线程对象为key,这个var2为值存入ThreadLocal中的。
接近 2 年之前 回复
wojiushiwo945you
wojiushiwo945you 回复zhuzhu923: 你这个set的值是当下线程对象的,ThreadLocal本意就是每个线程拥有一份数据的。所以在对应线程中的get操作也是对应线程set时的值的。
接近 2 年之前 回复
zhuzhu923
zhuzhu923 ThreadLocalUsage thread = new ThreadLocalUsage(); thread.start(); 这个地方是这个线程启动的地方 thread.user.set("var2"); 这边是对这个现场的user变量设置值,这个不是应该是同一个线程对象吗
接近 2 年之前 回复
zhuzhu923
zhuzhu923   2016.01.21 17:14

ThreadLocalUsage thread = new ThreadLocalUsage();
thread.start();
这个地方是这个线程启动的地方
thread.user.set("var2"); 这边是对这个现场的user变量设置值,这个不是应该是同一个线程对象吗

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!