java 多线程方法加锁获取自增变量重复问题

/**

  • 测试多线程并发获取唯一子增长的值
  • @author Administrator
    *
    */
    public class BB {
    private int increment = 0;

    final static Set set = new HashSet();
    final static List list = new ArrayList();
    public synchronized int getauto() {
    return increment++;
    }
    public static void main(String[] args) throws Exception {
    final BB b = new BB();
    Vector workers = new Vector();
    for (int i = 0; i < 2; i++) {
    final Thread t = new Thread(new Runnable() {

            @Override
            public void run() {
                synchronized (this) {
                    for (int j = 0; j < 10000; j++) {
                        int num = b.getauto();
                        System.out.println(String.valueOf(num));
                        set.add(num);
                        list.add(num);
                    }
                }
    
            }
        });
        workers.add(t);
        t.setName("thread-" + i);
        t.start();
    }
    for (Thread t : workers) {
        t.join();
    }
    System.out.println("set  size :" + set.size());
    System.out.println("list  size :" + list.size());
    

    }
    }
    list和set的size不同

System.out.println("set size :" + set.size());
System.out.println("list size :" + list.size());
这两句可没有在锁区域内,一个线程完毕后,在这两句执行的任意时刻,另一个线程可能已经开始执行,并改写了list

for (Thread t : workers) {
t.join();
}
这个是等待线程都执行完毕

System.out.println("set size :" + set.size());
System.out.println("list size :" + list.size());
这两句肯定是线程都执行完了,才打印出来的。预期结果set和list的size都是20000

hashset、arraylist是线程不安全的,你这样写,有时候会得到正确的长度。同步一下就好。。

你的工作线程的run方法中synchronize是用的this,是指当前线程对象,这样的话,每个线程都是有自己的this对象,所有线程run时锁都不一样,怎么能保证对共享变量的同步呢?那必定会出现同时操作set和list共享变量的情况啊
修正代码,使用外界共享对象作为锁,例如用final BB b,或者直接对list和set进行加锁,就能保证run中的代码每次只有一个线程能获取到锁。

 synchronized (b) {
                        for (int j = 0; j < 10000; j++) {
                            int num = b.getauto();
                            System.out.println(String.valueOf(num));
                            set.add(num);
                            list.add(num);
                        }
                    }

这个问题,主要是每个工作线程在run中用的锁不同,你的代码锁在线程对象this上,就相当于根本没有同步处理。