关于线程共享变量的一个问题

我写了这样一个测试程序:Runner是Runnable的实现类,类里面包含一个Object类型的私有变量,想通过这个程序测试看是否类的私有成员在多个线程中是否是共享的。

大多数的输出结果中没有重复的值,但是偶尔会出现相同的结果,不知道我的程序哪里出现问题了? 类的私有变量是不是多个线程共享的?

 

import java.util.ArrayList;
import java.util.List;
public class SharedVariableDemo {
 private static List<Thread> threadList = new ArrayList<Thread>();
 
 public static void main(String[] args) {

  
  for (int i = 0; i < 10; i++) {
   threadList.add(new Thread(new Runner()));
  }
  for (int i = 0; i < 10; i++) {
   Thread t = threadList.get(i);
   t.start();
  }
 }
}
class Runner implements Runnable {
 
 private Object obj = null;
 
 public Runner() {
  synchronized (this) {
   obj = new Object();
  }
 }
 
 public void run() {
  synchronized (this) {
   System.out.println(obj.toString());
  }
 }
}

 

输出结果:
java.lang.Object@10b30a7
java.lang.Object@89ae9e
java.lang.Object@60aeb0
java.lang.Object@66848c
java.lang.Object@1d58aae
java.lang.Object@de6f34
java.lang.Object@10d448        // 偶尔会出现值相同的情况。
java.lang.Object@10d448        //
java.lang.Object@e0e1c6
java.lang.Object@6ca1c


问题补充:
那么线程类的私有变量需要做同步处理吗?
问题补充:
那么是不是说:每个线程实例都有一个属于自己的私有空间,私有变量都是保存在这个私有空间的?

[quote="liugy52"]那么是不是说:每个线程实例都有一个属于自己的私有空间,私有变量都是保存在这个私有空间的? [/quote]

变量、常量这些东西都是讲究作用域,你可以理解为私有空间,但是jvm是不跟你谈私有空间这东西的,只认作用域。

呵呵,你的程序测试的是垃圾回收器。程序中new 了 100个Runner ,每次运行完毕都有可能垃圾回收,这样当前地址就有可能下次被重新分配。
在这里并没有看到线程发挥多大的作用,你应该这样:
1 定义一个变量封装的类 MyEncap ,封装 int i ,包含i 自增与自减方法与get方法。
2 ThreadA 初始化传入MyEncap 一个实例 my_encap,调用 MyEncap自增自减方法各一次,如此循环N 次,每次输出i 的值。
3 ThreadB 与ThreadA一样,要传入同一个MyEncap 的实例。
看看结果
再加sychornized关键子保护看看结果,了然。
建议读Thinking In Java,足够了。

这个问题有点奇怪,你加好多同步块,可能这些同步块搞得有问题,
我在我机器上跑了下,一直没出现这种现象

[quote]想通过这个程序测试看是否类的私有成员在多个线程中是否是共享的。[/quote]

这个能做到么?

[quote]类的私有变量是不是多个线程共享的?[/quote]
类的私有变量是属于某个对象的. 这个对象也当然可以被多个线程同时并发访问;
如果有必要,你可以对这个对象做并发控制;

[quote]但是偶尔会出现相同的结果,不知道我的程序哪里出现问题了? [/quote]
Object对象的toString()也是生成hashCode();
因为每次Object执行equals方法,都返回false;
所以,Java不保证每次返回的hashCode都唯一;

如果你把Object换成String,就更能说明问题.

嗯……建议先弄明白类变量和实例变量的区别

这代码本身好像就存在问题,创建对象的时候没必要加同步锁,看了代码,还是不知道你那里不明白!

局部变量,那要看相对性了。
如果说这个局部变量相对于调用它的类来说是非局部的,那么就有必要加安全了
例如在一个方法内声明一个变量,并在方法内有两个线程调用它,就得加synchronized关键字 呵呵

[quote]那么线程类的私有变量需要做同步处理吗? [/quote]

是否需要做同步,取决于你的变量是否会被多线程访问操作. 如果有这种情况,你需要做线程并发控制.否则就可以不用处理了.

[quote="liugy52"]那么线程类的私有变量需要做同步处理吗? [/quote]
在你这个demo下的场景,完全没必要加synchronized,加了就成了uncontended synchronization。

[quote]问题补充:
那么是不是说:每个线程实例都有一个属于自己的私有空间,私有变量都是保存在这个私有空间的? [/quote]

可以这么理解.
就跟多个 父进程/子进程,独立数据存储空间一样.
线程间也是独立.