日期:2014-05-20  浏览次数:20861 次

被synchronized块修饰的类成员变量和声明为static的类成员变量一样?
实例如下,定义了一个线程类MyThread,含有一个成员变量i,没有声明为static,为什么在synchronized块内操作后,类对象B得到的i值是上一个类对象A修改过的值呢?
这样不就和static类成员一样了吗?synchronized有此作用?

public class JavaTest {

/**
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("main start");
MyThread thread = new MyThread();
Thread a = new Thread(thread, "A");
Thread b = new Thread(thread, "B");
a.start();
b.start();

System.out.println("main end");
}

}

class MyThread implements Runnable {
private int i = 0;

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName() + " run enter i = " + i);
synchronized(this){
System.out.println(Thread.currentThread().getName() + " synchronized >>>>>>> i = " + i);
for (; i < 5; i++) {
//for (i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);
}
}

System.out.println(Thread.currentThread().getName() + " run exit");
}

}

输出结果:
main start
main end
A run enter i = 0
B run enter i = 0
A synchronized >>>>>>> i = 0
A synchronized loop 0
A synchronized loop 1
A synchronized loop 2
A synchronized loop 3
A synchronized loop 4
A run exit
B synchronized >>>>>>> i = 5 // 为什么i的值是5而不是0呢? 这样不就和static成员变量一样了?
B run exit
------解决方案--------------------
虽然有2个线程 , 但操作的是同一个对象。 
------解决方案--------------------
就相当于两个线程在轮番使用这个对象,只有一个对象
------解决方案--------------------
引用:
就相当于两个线程在轮番使用这个对象,只有一个对象

+1
------解决方案--------------------
Thread a = new Thread(thread, "A"); //a线程调用的是thread对象的run方法
Thread b = new Thread(thread, "B"); //b线程调用的也是thread对象的run方法
两个线程使用的都是同一个thread对象,所以两个线程之间相互产生影响

------解决方案--------------------
有两点:
第一,线程a和线程b同时使用thread对象,当线程a退出同步块后,i的值变成5
第二,由于同步块对变量的i的改变对其他线程可见,效果比volatile稍强,故其他线程也能看到这个值已经发生改变的值。
因为两个线程同时操作一个对象的同一个状态(这里是i),所以需要加同步块。
------解决方案--------------------
引用:
实例如下,定义了一个线程类MyThread,含有一个成员变量i,没有声明为static,为什么在synchronized块内操作后,类对象B得到的i值是上一个类对象A修改过的值呢?
这样不就和static类成员一样了吗?synchronized有此作用?

Java code
public class JavaTest {

    /**
     * @param args
     ……


是的,你测试的不对,都是对同一个thread操作。



package com.cybersoft.dsan.test;


public class JavaTest {
/**
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("main start");
MyThread aa = new MyThread("A");
MyThread bb = new MyThread("B");
Thread a = new Thread(aa);
Thread b = new Thread(bb);
a.start();
b.start();

System.out.println("main end");
}

}

class MyThread implements Runnable {
private String threadName;
public MyThread(String threadName){
this.threadName = threadName;
}
private int i = 0;

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(threadName + " run enter i = "
+ i);
synchronized (this) {
System.out.println(threadName
+ " synchronized >>>>>>> i = " + i);
for (; i < 5; i++) {
// for (i = 0; i < 5; i++) {
System.out.println(threadName
+ " synchronized loop " + i);
}
}

System.out.println(threadName + " run exit");
}
}



改成类似于上面,就应该i的值不会相互影响。