欢迎使用CSDN-markdown编辑器

来源:互联网 发布:手机淘宝积分在那里看 编辑:程序博客网 时间:2024/06/05 04:33
最近在做项目时,看到这么一个代码。多线程会共同访问的一个类的方法,该类在调用时,所有的线程只会访问同一个实例对象,该类大概如下(非原码,参考用):
    public class class1 {    private Map<String, Object> map = new HashMap();;    public void me1(String s){        map.clear();        map.put("me1", "me1");        map.put(s, s);        System.out.println("调用者:"+s+":"+Thread.currentThread().getId()+":"+map);    }    public void me2(String s){        map.clear();        map.put("me2", "me2");        map.put(s, s);        System.out.println("调用者:"+s+":"+Thread.currentThread().getId()+":"+map);    }    public void me3(String s){        map.clear();        map.put("me3", "me3");        map.put(s, s);        System.out.println("调用者:"+s+":"+Thread.currentThread().getId()+":"+map);    }}
可以看到,这个类成员中有一个Map集合,所有的方法都会访问这个map,在使用Map存值前调用clear方法清空。看上去像没什么问题,但是在多线程访问一个对象的时候,用M。这种是无法保证值的正确性。测试一下

public class test {

public static void main(String[] args) {    final class1 c = new class1();    Thread t1 = new Thread(new Runnable() {                 @Override        public void run() {            c.me1("t1");        }    });    Thread t2 = new Thread(new Runnable() {                 @Override        public void run() {            c.me2("t2");        }    });    Thread t3 = new Thread(new Runnable() {                 @Override        public void run() {            c.me3("t3");        }    });//  for(int x=0;x<10;x++){        t1.start();        t2.start();        t3.start();     //}}

}
创建三个线程,分别访问调用这个对象的三个方法,结果如下:
结果1:
调用者:t2:11:{me2=me2, t2=t2}
调用者:t1:10:{me2=me2, t2=t2}
调用者:t3:12:{me2=me2, t2=t2}
结果2:
调用者:t1:10:{me3=me3, t3=t3}
调用者:t3:12:{me3=me3, t3=t3}
调用者:t2:11:{me3=me3, t3=t3}

很明显,在多线程访问时,值不对。
如果我每个线程都去new一个新的对象,结果肯定是对的。代码如下:
public class test {

public static void main(String[] args) {//  final class1 c = new class1();    Thread t1 = new Thread(new Runnable() {                 @Override        public void run() {            class1 c = new class1();            c.me1("t1");        }    });    Thread t2 = new Thread(new Runnable() {                 @Override        public void run() {            class1 c = new class1();            c.me2("t2");        }    });    Thread t3 = new Thread(new Runnable() {                 @Override        public void run() {            class1 c = new class1();            c.me3("t3");        }    });//  for(int x=0;x<10;x++){        t1.start();        t2.start();        t3.start();     //}}

}

结果:
调用者:t3:12:{me3=me3, t3=t3}
调用者:t2:11:{me2=me2, t2=t2}
调用者:t1:10:{me1=me1, t1=t1}

这样数据也是对的,但是,这样在我的项目中肯定是不行的,因为公司框架的原因,只能去调用同一个对象。所以只能把类改掉,如下:

public class class1 {

public void me1(String s){    Map<String, Object> map = new HashMap();    map.clear();    map.put("me1", "me1");    map.put(s, s);    System.out.println("调用者:"+s+":"+Thread.currentThread().getId()+":"+map);}public void me2(String s){    Map<String, Object> map = new HashMap();    map.clear();    map.put("me2", "me2");    map.put(s, s);    System.out.println("调用者:"+s+":"+Thread.currentThread().getId()+":"+map);}public void me3(String s){    Map<String, Object> map = new HashMap();    map.clear();    map.put("me3", "me3");    map.put(s, s);    System.out.println("调用者:"+s+":"+Thread.currentThread().getId()+":"+map);}

}

OK,这样基本就没问题了,调用方法的时候在方法里面去创建map集合,这样就能避免数据乱掉的问题。

原创粉丝点击