使用Integer作为同步信号引起的不同步问题
|
|
1 # 大 中 小 发表于 2010-01-13 07:27:14
问题一:
class ThreadTest extends Thread {
Integer counter = 0;
public void run() {
synchronized (counter) {
for (int i = 0; i < 10; i++) {
++counter;
System.out.println(Thread.currentThread().getName() + " "
+ counter);
try {
Thread.sleep(1000);
} catch (Exception e) {
}
}
}
}
public static void main(String args[]) {
Thread t1 = new ThreadTest();
Thread t2 = new ThreadTest();
t1.start();
t2.start();
try{
t1.join();
t2.join();
} catch (Exception e){
}
}
}
结果(运行多次,始终是这个结果): Thread-0 1 Thread-0 2 Thread-0 3 Thread-0 4 Thread-0 5 Thread-0 6 Thread-0 7 Thread-0 8 Thread-0 9 Thread-0 10 Thread-1 1 Thread-1 2 Thread-1 3 Thread-1 4 Thread-1 5 Thread-1 6 Thread-1 7 Thread-1 8 Thread-1 9 Thread-1 10 我的理解: 我创建了两个Thread instances, 每个instance有自己的instance variable counter(Integer类型),我认为虽然run里面对counter object进行了同步,但是每个instance拥有自己的counter object,不干扰,所以其实同步没有什么作用。但实际的结果是thread0做完了,thread再做,请问为什么? 问题二:
class ThreadTest extends Thread {
static Integer counter = 0;
public void run() {
synchronized (counter) {
for (int i = 0; i < 10; i++) {
++counter;
System.out.println(Thread.currentThread().getName() + " "
+ counter);
try {
Thread.sleep(1000);
} catch (Exception e) {
}
}
}
}
public static void main(String args[]) {
Thread t1 = new ThreadTest();
Thread t2 = new ThreadTest();
t1.start();
t2.start();
try{
t1.join();
t2.join();
} catch (Exception e){
}
System.out.println(ThreadTest.counter);
}
}
结果(不唯一,很多种): Thread-0 2 Thread-1 2 Thread-0 3 Thread-1 3 Thread-0 5 Thread-1 5 Thread-1 6 Thread-0 7 Thread-1 8 Thread-0 8 Thread-1 10 Thread-0 10 Thread-0 12 Thread-1 12 Thread-1 14 Thread-0 14 Thread-1 15 Thread-0 16 Thread-0 18 Thread-1 18 18 我的理解: 问题二中代码与问题一代码不同的地方是,将counter声明为static,并在两个线程结束后显示最终counter的值。我的理解是,在这里两个instance公用一个声明为static 的 class variable counter,如果在run中对counter进行同步,应该的出像问题一中给出的那样的结果。但结果显示,根本没有同步,交替执行。如果以每个java语句为最小执行粒度考虑,counter最终结果无论同步与否,都应是20,而实际上15,16,17等都有可能,原因是不是因为:实际最小执行粒度为微指令,可能 - thread0 刚取出counter当前值14,还未进行加操作就转向thread1,thread1也取出14,加1,并将结果15放入counter寄存器。然后转向thread0,thread0在刚才取出14上加1,得15,并将counter的值再次更新为15,导致两次加1操作实际上只加了一个1,所以最终结果可能小于20.请指教。 问题三:
class ThreadTest extends Thread {
static Integer counter = 0;
public void run() {
synchronized (ThreadTest.class) {
for (int i = 0; i < 10; i++) {
++counter;
System.out.println(Thread.currentThread().getName() + " "
+ counter);
try {
// System.out.println(Thread.currentThread().getName() +
// " sleep");
Thread.sleep(1000);
} catch (Exception e) {
}
}
}
}
public static void main(String args[]) {
Thread t1 = new ThreadTest();
Thread t2 = new ThreadTest();
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (Exception e) {
}
System.out.println(ThreadTest.counter);
}
}
结果(运行多次,结果一样) Thread-0 1 Thread-0 2 Thread-0 3 Thread-0 4 Thread-0 5 Thread-0 6 Thread-0 7 Thread-0 8 Thread-0 9 Thread-0 10 Thread-1 11 Thread-1 12 Thread-1 13 Thread-1 14 Thread-1 15 Thread-1 16 Thread-1 17 Thread-1 18 Thread-1 19 Thread-1 20 20 我的理解: 问题三代码与问题二代码唯一不同之处是将synchronized (counter)改为synchronized (ThreadTest.class)。我的理解是,此时一个线程将获得class的锁(而不是instance的锁),保证对static 的 class variable进行更新同步,所以结果是同步的。我的理解对吗?平常见到的例子都是在static method中用这个(我的例子中run不是static的),比如:
public static int getCount(){
synchronized(MyClass.class){
return count;
}
}
请指教。 谢谢大家! Integer counter = 0; 你知道Integer 是什么吗?是不可更改的!!!!! 任何对Integer的更改都会造成生成一个新的Integer 记住一点:不要使用不可更改的对象组为同步对象,却对这个对象进行了更高,包括String. 当然,你设置为 final 是可行的选择 private final Integer counter = 0;
快乐渡过每一天,减肥坚持每一天
|
|||||
|


