我尝试使用多线程来访问Hashtable,因为Hashtable在get上是线程安全的。但我无法让它发挥作用。
我认为本地计数器的总和应该等于Hashtable或global_counter的大小。但事实并非如此。
多个线程获取java.util.NoSuchElementException:Hashtable Enumerator错误。我认为错误是由Hashtable的枚举引起的。是这样吗?
TestMain:
public class TestMain {
// MAIN
public static void main(String argv[]) throws InterruptedException
{
Hashtable<Integer, Integer> id2 = new Hashtable<Integer, Integer>();
for (int i = 0; i < 100000; ++i)
id2.put(i, i+1);
int num_threads = Runtime.getRuntime().availableProcessors() - 1;
ExecutorService ExeSvc = Executors.newFixedThreadPool(num_threads);
for (int i = 0; i < num_threads; ++i)
{
ExeSvc.execute(new CalcLink(id2, i));
}
ExeSvc.shutdown();
ExeSvc.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
}
}
CalcLink:
public class CalcLink implements Runnable {
private Hashtable<Integer, Integer> linktable;
private static Enumeration keys;
private static int global_counter;
private int thread_id;
private int total_size;
public CalcLink(Hashtable<Integer, Integer> lt, int id)
{
linktable = lt;
keys = lt.keys();
thread_id = id;
total_size = lt.size();
global_counter = 0;
}
private synchronized void increment()
{
++global_counter;
}
@Override
public void run()
{
int counter = 0;
while (keys.hasMoreElements())
{
++counter;
increment();
Integer key = (Integer)keys.nextElement();
Integer value = linktable.get(key);
}
System.out.println("local counter = " + Integer.toString(counter));
if (thread_id == 1)
System.out.println("global counter = " + Integer.toString(global_counter));
}
}
答案 0 :(得分:0)
while (keys.hasMoreElements()) // here you check whether there's an element
{
++counter; // other stuff...
increment(); // other stuff...
Integer key = (Integer)keys.nextElement(); // only here you step
在你进入&#34;其他东西的过程中,这个帖子&#34;你可以在另一个线程中输入其他内容,因此恕我直言,你可能会看到全局计数器中的数字比你预期的更多。
这也是你在某些线程中看到NoSuchElementException的原因,这些线程进入&#34;其他东西&#34;在一起,但正试图抓住最后一个元素。后来的线程在到达nextElement();
时不会有元素答案 1 :(得分:0)
问题是此块未同步:
while (keys.hasMoreElements())
{
++counter;
increment();
Integer key = (Integer)keys.nextElement();
Integer value = linktable.get(key);
}
当枚举中只有一个元素时, keys.hasMoreElements()
可以在多个线程中评估为true
。在这些主题中:第一个到达keys.nextElement()
会很好,但所有其他人都会提出NoSuchElementException
试试这个:
@Override
public void run()
{
int counter = 0;
synchronized (keys){
while (keys.hasMoreElements())
{
++counter;
increment();
Integer key = (Integer)keys.nextElement();
Integer value = linktable.get(key);
}
}
System.out.println("local counter = " + Integer.toString(counter));
if (thread_id == 1)
System.out.println("global counter = " + Integer.toString(global_counter));
}
答案 2 :(得分:0)
一个天真的解决方案:我让每个线程处理记录的长度/ num_threads。只有最后一个线程将处理length / num_threads + length%num_threads记录。