java多线程中的可见性问题

ludevica 2011-06-09 10:50:04
新建了一个线程类,构造参数为一个String,在run方法内将这个通过构造参数传入的String改个值,这个线程类就算完事了。
随后在另一个客户端类(main方法)中定义一个String并赋初始值。随后new一个先前创建的线程类,并将这个String作为构造参数传入。随后打印这个String。按照预期,打印出的应该是在线程类中run方法改过值后的结果,但结果却是这个Sting的初始值。即这个Sring被一个线程改过值后,回到主线程中并没有改变值。请高人赐教原因!!!代码大致如下:
public static void main(String[] args){
String name = "original";
Thread t = new Thread4(name);
t.start();
t.join();
System.out.println(name);
}

public class Thread4 extends Thread {

@Override
public void run() {
name = "changed";
System.out.println("changing name to :" + name);
}

String name;

public Thread4(String name){
this.name = name;
}
}
令我诧异的是,修改这个线程类的构造参数,传入一个自定义的对象,随后再run方法中更改传入对象的一个域,也是Stirng类型的。随后和上面的代码类似,在主线程中打印这个对象的域值,结果是改变后的值。问题是为什么Sting在一个线程中被更改后在主线程中看不见被更改后的结果,而自定义对象的String的域却可以??
...全文
269 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
lliiqiang 2011-06-10
  • 打赏
  • 举报
回复
这个问题还是常见的引用传值和数值传值的区别.

传递给线程的只是字符串地址,线程将地址赋给新的变量,线程改变的是新变量,新变量是从原来传递的变量获取地址.原来的变量还是不变
qybao 2011-06-10
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 ludevica 的回复:]
首先感谢赐教,开发java有一段时日了,但是这个看似简单的问题却把我搞的有点糊涂了。首先我认为String在java中是引用类型。在调用了change方法后,将传入的name指向了"new",那在main方法中该是打印出"new",真不明白为什么还是"old"?
[/Quote]
我在2L的解释很清楚了
public static void main(String[] args) {
String s = "old"; //这里的s相当于2L的代码的s1
change(s);
System.out.println(s);
}

public static void change(String s) {
s = "new"; //注意这里的s相当于2L的代码的s2
}


首先要知道,每个方法都有自己的栈,方法内部的变量是在自己的方法栈里面的,也就是说change方法的s和main方法的s不是同一个,是各自方法栈里的变量,它们只是值相同,即它们都指向同一个字符串对象(也就是说它们引用的是同一个字符串对象),所以改变change方法的s,让它指向新的字符串对象(即让change的s引用新的字符串对象),并不会影响main方法的s(即main的s引用并没有发生任何改变),因为它们是互不相干的
再来看一段代码
public static void main(String[] args) {
StringBuilder s = new StringBuilder("old");
change(s);
System.out.println(s);
}

public static void change(StringBuilder s) {
s.append("new"); //注意这个例子和上面的例子的区别,这里发生的不是s=这样的处理
//也就是说没有发生s指向的改变,即change里的s和main里的s还是引用同一个对象
s.append("I am the same value of s of main."); //所以这里发生的改变会影响main的s
//因为append是操作change的s所引用的对象的方法,
//而main的s也在引用这个对象,所以方法发生的效果会影响到main的s

s = new StringBuilder("change"); //注意这里,发生了s=这样的处理,也就是说改变了s的指向,
//即change里的s和main里的s不再指向同一个对象
//change的s引用了新的对象,而main的s还是引用原来的对象
s.append("I am not the same s of main"); //所以这里再发生变化,也不会影响main的s
}



ludevica 2011-06-09
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 qybao 的回复:]
LZ能理解下面这段代码的问题,就清楚自己的问题了

Java code
public static void main(String[] args) {
String s = "old";
change(s);
System.out.println(s);
}

public static void change(String s) {
s = ……
[/Quote]
首先感谢赐教,开发java有一段时日了,但是这个看似简单的问题却把我搞的有点糊涂了。首先我认为String在java中是引用类型。在调用了change方法后,将传入的name指向了"new",那在main方法中该是打印出"new",真不明白为什么还是"old"?
qybao 2011-06-09
  • 打赏
  • 举报
回复
举个更简单一点的例子吧

String s1 = "old";
String s2 = s1; //这里就当作是s1传到方法,使得方法的参数s2=s1,
//其实就是让方法的参数指向了和方法外的s1一样的内存地址
s2 = "new"; //这里就当作是方法的参数s2改变了,
//要注意,这里是改变了s2,让它指向新的内存地址,但是s1本身没有任何改变
System.out.println(s1); //所以方法外的s1并没有变
qybao 2011-06-09
  • 打赏
  • 举报
回复
LZ能理解下面这段代码的问题,就清楚自己的问题了
public static void main(String[] args) {
String s = "old";
change(s);
System.out.println(s);
}

public static void change(String s) {
s = "new";
}

62,614

社区成员

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

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