我已经写了一些代码来同时通过两个线程遍历一个Thread-safe Hashtable
。预计从下面的代码中一次只能读取一个线程 -
class Test7 extends Thread{
static Hashtable t=new Hashtable();
static Iterator it=t.entrySet().iterator();
public static void main(String[] args) throws InterruptedException{
t.put(1,"a");
t.put(2,"b");
t.put(3,"c");
t.put(4,"d");
t.put(5,"e");
Test7 q=new Test7();
q.start();
while(it.hasNext()){
out.println("Parent thread");
Map.Entry m1=(Map.Entry)it.next();
out.println(m1);
Thread.sleep(2000);
}
}
public void run(){
Iterator it=t.entrySet().iterator();
while(it.hasNext()){
out.println("Child thread");
Map.Entry m2=(Map.Entry)it.next();
out.println(m2);
try{
Thread.sleep(2000);
}
catch(InterruptedException e){
out.println(1);
}
}
}
}
输出在程序终止之后 -
Child thread
5=e
Child thread
4=d
Child thread
3=c
Child thread
2=b
Child thread
1=a
为什么父线程在此之后不执行?任何线索都会有所帮助,我们将不胜感激。
代码的第一个问题是在将任何条目添加到Hashtable
之前为主线程创建迭代器。对于这种特殊情况,entrySet().iterator()
方法返回一个java.utils.Collections.EmptyIterator
,其hasNext()
方法总是返回false。
如果你在while循环之前创建迭代器,主线程也将返回Hashtable
中的条目:
it=t.entrySet().iterator();
while(it.hasNext()){
out.println("Parent thread");
//...
}
但这只会导致交错输出:
Parent thread
Child thread
5=e
5=e
Child thread
4=d
Parent thread
4=d
Child thread
3=c
为什么?因为尽管Hashtable
(如put
,putAll
,get
,size
等)的访问方法是同步的,但是你可以创建的迭代器通常不会同步,除了remove
方法。
特别是在Hashtable
上进行迭代并不会阻止其他线程迭代它,就像你期望的那样。