问题描述
- 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是线程不安全的,你这样写,有时候会得到正确的长度。同步一下就好。。
解决方案五:
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上,就相当于根本没有同步处理。