java多线程访问Hashtable

时间:2016-02-02 20:55:04

标签: java multithreading hashtable

我尝试使用多线程来访问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));
    }
}

3 个答案:

答案 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记录。