有一个主列表,其中每个条目都包含一个字符串数组。还有一个从属列表,它实际上是一个散列集,每个条目都是一个字符串。我写了两个线程来搜索主列表中从属列表中的项目。
有一个stat的成员类,我在发出线程之前初始化它(而不是构造函数)。当他想要搜索主列表中的从属项时,每个线程将stat递增1。
在实际代码中,每个线程的主列表都是唯一的,以下示例代码使用一个主列表用于两个线程。
class myClass {
private List<String []> mainList;
private HashSet<String> slaveList;
private int nThread;
private int stat;
public myClass(int i)
{
nThread = i;
mainList = new ArrayList<>();
slaveList = new HashSet<>();
String [] str1 = {"a1", "a2", "a3"};
String [] str2 = {"b1", "b2", "b3"};
mainList.add(str1); mainList.add(str2);
slaveList.add("b2"); slaveList.add("a3");
}
public void doProcess() {
stat = 0;
for (int i = 0; i < nThread; i++) {
final int index = i;
final List<String []> m = mainList;
final HashSet<String> s = slaveList;
new Thread(() -> {
search(m, s, index);
System.out.println("done");
}).start();
}
}
public void search( List<String []> m, HashSet<String> s, int index )
{
Iterator<String> itr;
for ( int x = 0; x < m.size(); x++ ) {
itr = s.iterator();
while(itr.hasNext()){
++stat;
System.out.println("index=" + index + " master id=" + x + " slave=" + itr.next() + " stat=" + stat);
}
}
}
}
public class Threadtest {
public static void main(String[] args) {
myClass mc = new myClass(2);
mc.doProcess();
}
}
然而输出看起来很奇怪!!
index=0 master id=0 slave=b2 stat=1
index=1 master id=0 slave=b2 stat=1
index=0 master id=0 slave=a3 stat=2
index=1 master id=0 slave=a3 stat=3
index=0 master id=1 slave=b2 stat=4
index=1 master id=1 slave=b2 stat=5
index=0 master id=1 slave=a3 stat=6
index=1 master id=1 slave=a3 stat=7
done
done
第二行应打印stat=2
。似乎这里存在并发问题。第二个线程读取stat
的旧值,即0,但第一个线程必须在第二个线程之前将其递增1。
另一次运行的输出是
index=0 master id=0 slave=b2 stat=2
index=0 master id=0 slave=a3 stat=3
index=0 master id=1 slave=b2 stat=4
index=1 master id=0 slave=b2 stat=2
index=0 master id=1 slave=a3 stat=5
index=1 master id=0 slave=a3 stat=6
done
index=1 master id=1 slave=b2 stat=7
index=1 master id=1 slave=a3 stat=8
done
如您所见,统计数据在第一行打印为2! 怎么解决?
答案 0 :(得分:1)
答案 1 :(得分:1)
您可以同步使用共享变量的部分:
while(itr.hasNext()){
int localStat;
synchronized(this) {
localStat = ++stat;
}
System.out.println("index=" + index + " master id=" + x + " slave=" + itr.next() + " stat=" + localStat );
}
但这些名单仍然是共享的,没有受到保护。