解决方案 »

  1.   

    public class ThreadMain {
    Map<String,A> m = new HashMap<String, A>();

    void putA(A a){
    m.put("k", a);
    }

    void main(A a) {
    int i = 10;
    while(i > 0) {
    B b = new B();
    b.setValue(i);
    a.setB(b);

    R r = new R(m);
    Thread t = new Thread(r);
    t.start();
    i--;

    try {
    t.join();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }


    }
    }

    public static void main(String[] args) {
    ThreadMain d = new ThreadMain();
    A a = new A();
    d.putA(a);
    d.main(a);
    }
    }class R implements Runnable{
    Map<String,A> m;

    R(Map<String,A> m){
    this.m = m;
    } public void run() {
    A a = m.get("k");
    System.out.println("before set A.b.value is:"+a.getB().getValue());

    B b = new B();
    b.setValue(8888);
    a.setB(b);

    System.out.println("after set A.b.value is:"+a.getB().getValue());
    }
    }class A {
    private B b;
    public B getB() {
    return b;
    } public void setB(B b) {
    this.b = b;
    }
    }class B{
    private int value; public int getValue() {
    return value;
    } public void setValue(int value) {
    this.value = value;
    }
    }
      

  2.   

    楼上的方法是有点取巧了,把多线程变成单线程运行了。
    楼主的类里主线程里对A的实例做了改变,而在子线程里也对A的实例做了改变,所里这里做不了同步,应该把对A的修改全放在子线程里,把修改的代码块加上同步锁即可。如下:import java.util.HashMap;
    import java.util.Map;public class ThreadMain {
        Map<String,A> m = new HashMap<String, A>();

    void putA(A a){
    m.put("k", a);
    }

    void main(A a) {
    int i = 10;
    while(i > 0) {
    // B b = new B();
    // b.setValue(i);
    // a.setB(b);

    R r = new R(m,i);
    Thread t = new Thread(r);
    t.start();
    i--; }
    }

    public static void main(String[] args) {
    ThreadMain d = new ThreadMain();
    A a = new A();
    d.putA(a);
    d.main(a);
    }
    }class R implements Runnable{
    Map<String,A> m;
    int i;

    R(Map<String,A> m,int i){
    this.m = m;
    this.i = i;
    } public void run() {
    synchronized(ThreadMain.class){
    A a = m.get("k");
        B b = new B();
        b.setValue(i);
        a.setB(b);
    System.out.println("before set A.b.value is:" + a.getB().getValue()); b = new B();
    b.setValue(8888);
    a.setB(b); System.out.println("after set A.b.value is:" + a.getB().getValue());
    }
    }
    }class A {
    private B b;
    public B getB() {
    return b;
    } public void setB(B b) {
    this.b = b;
    }
    }class B{
    private int value; public int getValue() {
    return value;
    } public void setValue(int value) {
    this.value = value;
    }
    }
      

  3.   

    大大说的是,这么写代码是因为生产代码就是这样的,我还没到重构的水平。
    原代码这么写是为了方便Map作为全局缓存对里面的对象根据不同的条件赋值再在其他类里面使用,我觉得也有点别扭,而且现在在多线程的情况下又出现了好麻烦的bug
      

  4.   

    请问为什么把46行换成如下:
    synchronized (this){
    输出的结果有可能就不对了,执行多次后,出现如下结果:
    before set A.b.value is:10
    after set A.b.value is:8888
    before set A.b.value is:8
    after set A.b.value is:8888
    before set A.b.value is:6
    after set A.b.value is:8888
    before set A.b.value is:9
    after set A.b.value is:8888
    before set A.b.value is:4
    after set A.b.value is:8888
    before set A.b.value is:2
    after set A.b.value is:8888
    before set A.b.value is:7
    before set A.b.value is:8888
    after set A.b.value is:8888
    after set A.b.value is:8888
    before set A.b.value is:3
    after set A.b.value is:8888
    before set A.b.value is:1
    after set A.b.value is:8888观察红色部分,显然,synchronized块执行的过程中,被其他线程打断了,难道对R对象加锁之后,没有完全锁住吗?请大哥分析一下
      

  5.   

    把同步块代码改成synchronized (this),是不能达到锁的 效果的。因为this代表的是当前线程对象,所以是对当前的线程对象加锁。也就是说每个线程都只是各自拥有了一把锁,这样锁的意义就失效。
    而synchronized(ThreadMain.class)是对全局加锁,所以能到到达互斥的效果!
      

  6.   

    楼主的程序中的M实例自始至终只有一个,所有的操作都是对M的一个实例的操作,当所有的线程开始时,m.a.b.value都已经从10,9,变到1。要想能输出123...... .必须每个循环创造一个实例。要真想只用一个实例,就不要用线程了,循环一个一个操作。
      

  7.   

    程序略作修改。ThreadMain 给R传m后,不要直接用this.m=m;因为是引用类型,两个m指向的是同一个实例,每个线程操作的都是你ThreadMain的m。R中m重新new一个,下面的a,b都要new,只复制个value。 
    import java.util.Map;
    import java.util.HashMap;public class ThreadMain {
    Map<String,A> m = new HashMap<String, A>();

    void putA(A a){
    m.put("k", a);
    }
    void main(A a) {
    int i = 10;
    while(i > 0) {
    B b = new B();
                b.setValue(i);
                a.setB(b);
    R r = new R(m);
    Thread t = new Thread(r);
    t.start();
    i--;
    }
    }

    public static void main(String[] args) {
    ThreadMain d = new ThreadMain();
    A a=new A();
    d.putA(a);
    d.main(a);
    }
    }class R implements Runnable{
    Map<String,A> m;

    R(Map<String,A> m){
    A a=m.get("k");
    B b=a.getB();
    int v=b.getValue();
    B b1=new B();
    b1.setValue(v);
    A a1=new A();
    a1.setB(b1);
    this.m = new HashMap<String, A>();
    this.m.put("k", a1);
    } public void run() {

    A a = m.get("k");
    System.out.println("before set A.b.value is:"+a.getB().getValue());

    B b = new B();
    b.setValue(8888);
    a.setB(b);

    System.out.println("after set A.b.value is:"+a.getB().getValue());
    }
    }class A {
    private B b;
    public B getB() {
    return b;
    } public void setB(B b) {
    this.b = b;
    }
    }class B{
    private int value; public int getValue() {
    return value;
    } public void setValue(int value) {
    this.value = value;
    }
    }
      

  8.   

    懂了,分析的非常透彻,多谢!
    补充一点,this代表的是R对象,因为每次循环都是new R(), 所以synchronized(this)是分别对每个R对象加锁,这些锁之间互不干扰,所以每个线程都能拿到自己的R对象锁然后执行synchronized块里的代码,这样就是锁不住的原因;如果R对象是单例的,每次循环拿到的都是同一个R对象,那么synchronized(this)就是对单例的那个R对象加锁,自始至终只有这一个锁,这样的话每个线程要想执行synchronized块里的代码,必须得拿到那个唯一的R对象锁,这样就起到锁的作用了。
    以上是我个人的理解,有不对的地方请指出,谢谢!