ThreadLocal的疑问?

confirmAname 2014-04-02 01:46:01
贴上代码:

class Account
{
/* 定义一个ThreadLocal类型的变量,该变量将是一个线程局部变量
每个线程都会保留该变量的一个副本 */
private ThreadLocal<String> name = new ThreadLocal<String>();
// 定义一个初始化name属性的构造器
public Account(String str)
{
this.name.set(str);
// 下面代码用于访问当前线程的name副本的值
System.out.println("---" + this.name.get());
}
// name的setter和getter方法
public String getName()
{
return name.get();
}
public void setName(String str)
{
this.name.set(str);
}
}
class MyTest extends Thread
{
// 定义一个Account属性
private Account account;
public MyTest(Account account, String name)
{
super(name);
this.account = account;
}
public void run()
{
// 循环10次
for (int i = 0 ; i < 10 ; i++)
{
// 当i == 6时输出将账户名替换成当前线程名
if (i == 6)
{
account.setName(getName());
}
// 输出同一个账户的账户名和循环变量
System.out.println(account.getName()
+ " 账户的i值:" + i);
}
}
}
public class ThreadLocalTest
{
public static void main(String[] args)
{
// 启动两条线程,两条线程共享同一个Account
Account at = new Account("初始名");
/*
虽然两条线程共享同一个账户,即只有一个账户名
但由于账户名是ThreadLocal类型的,所以每条线程
都完全拥有各自的账户名副本,所以从i == 6之后,将看到两条
线程访问同一个账户时看到不同的账户名。
*/
new MyTest(at , "线程甲").start();
new MyTest(at , "线程乙").start ();
}
}

运行后控制台输出:

我的困惑是:为什么在i变为6之前,account.getName()的输出为null?主线程启动的两个线程的构造器里都传入了at,那么,这个account.getName()为什么不输出为“初始名”呢,不是副本吗,副本应该和本体一样才对啊?求高人讲解。。。
...全文
389 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
44233_hangyu 2014-11-17
  • 打赏
  • 举报
回复
什么情景下使用ThreadLocal比较好?什么情景下使用同步比较好啊?
humanity 2014-11-17
  • 打赏
  • 举报
回复
引用 11 楼 huanongying131 的回复:
public T get()返回此线程局部变量的当前线程副本中的值。如果变量没有用于当前线程的值,则先将其初始化为调用 initialValue() 方法返回的值。 返回此线程局部变量的当前线程的“初始值”。线程第一次使用 get() 方法访问变量时将调用此方法,但如果线程之前调用了 set(T) 方法,则不会对该线程再调用 initialValue 方法。通常,此方法对每个线程最多调用一次,但如果在调用 get() 后又调用了 remove(),则可能再次调用此方法。 该实现返回 null;如果程序员希望线程局部变量具有 null 以外的值,则必须为 ThreadLocal 创建子类,并重写此方法。通常将使用匿名内部类完成此操作。
+1 创建匿名内部类覆盖它的 initialValue() 方法返回一个默认值就好了,只要你觉得有默认值是设计要求的就可以这么做,多数时候并不需要默认值。
huanongying131 2014-11-17
  • 打赏
  • 举报
回复
public T get()返回此线程局部变量的当前线程副本中的值。如果变量没有用于当前线程的值,则先将其初始化为调用 initialValue() 方法返回的值。 返回此线程局部变量的当前线程的“初始值”。线程第一次使用 get() 方法访问变量时将调用此方法,但如果线程之前调用了 set(T) 方法,则不会对该线程再调用 initialValue 方法。通常,此方法对每个线程最多调用一次,但如果在调用 get() 后又调用了 remove(),则可能再次调用此方法。 该实现返回 null;如果程序员希望线程局部变量具有 null 以外的值,则必须为 ThreadLocal 创建子类,并重写此方法。通常将使用匿名内部类完成此操作。
求注销 2014-06-15
  • 打赏
  • 举报
回复
ThreadLocal可以理解为一个Map<Thread_ID,Value>, 实例化Account时相当于 Map.put(主线程_Id,"初始名"); 线程甲启动后,在循环输出中name.getName相当于 return Map.get(线程甲_Id),故返回值为null。 希望可以帮到你
zuokeli1988 2014-06-11
  • 打赏
  • 举报
回复
三楼是对的threadlocal奥妙在此
yuhouqingchen_2648 2014-06-11
  • 打赏
  • 举报
回复
引用 5 楼 lq83205823 的回复:
[quote=引用 3 楼 java_liyi 的回复:] 基本上原因就是ThreadLocal中set的对象只能为本线程所看见,不能被其他线程看见 对于上面的代码,Account实例化时,成员name.set()的对象只能被main线程取出,而后面的线程甲、乙并不能获取到该Account对象的成员name中set的对象,所以并不会有什么name中存放对象的副本什么的。
+1[/quote] 我试验过,绝对正解
zxj828282 2014-04-03
  • 打赏
  • 举报
回复
top top top
軒轅劍 2014-04-02
  • 打赏
  • 举报
回复
引用 3 楼 java_liyi 的回复:
基本上原因就是ThreadLocal中set的对象只能为本线程所看见,不能被其他线程看见 对于上面的代码,Account实例化时,成员name.set()的对象只能被main线程取出,而后面的线程甲、乙并不能获取到该Account对象的成员name中set的对象,所以并不会有什么name中存放对象的副本什么的。
+1
java_liyi 2014-04-02
  • 打赏
  • 举报
回复
否则如果能看见这个被set的对象,就意味着甲乙线程能看见这个对象的引用,那么当修改对象时,就不能实现甲乙分别设置了一个name,这与ThreadLocal的设计是违背的。
java_liyi 2014-04-02
  • 打赏
  • 举报
回复
基本上原因就是ThreadLocal中set的对象只能为本线程所看见,不能被其他线程看见 对于上面的代码,Account实例化时,成员name.set()的对象只能被main线程取出,而后面的线程甲、乙并不能获取到该Account对象的成员name中set的对象,所以并不会有什么name中存放对象的副本什么的。
harrisonkao 2014-04-02
  • 打赏
  • 举报
回复
不好意思,看错了,感觉对了啊
harrisonkao 2014-04-02
  • 打赏
  • 举报
回复
在6之前你没有将name保存到线程的account对象里

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧