简体   繁体   中英

java multi threads access Hashtable

I tried to use multi threads to access the Hashtable, since Hashtable is thread safe on get. But I cannot get it work.

I thought the sum of local counter should be equal to the size of the Hashtable or the global_counter. But it is not.

Serveral threads get java.util.NoSuchElementException: Hashtable Enumerator error. I think the error is due to the enumeration of Hashtable. Is that so?

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));
    }
}
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

During you are in the other stuff in "this thread" you can enter the other stuff in another thread, thus IMHO you might see higher number in the global counter than what you expect.

This is also the reason you see NoSuchElementException in some of the threads, that entered to the "other stuff" together, but are trying to catch the last element. The later threads won't have the element there when they get to nextElement();

The problem is that this block isn't synchronized :

while (keys.hasMoreElements())
{
    ++counter;
    increment();
    Integer key = (Integer)keys.nextElement();
    Integer value = linktable.get(key);
}

keys.hasMoreElements() can be evaluated to true in multiple threads when there is still only one element in the Enumeration. In those threads : the first one reaching keys.nextElement() will be fine, but all the others will raise a NoSuchElementException

Try this :

@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));
}

An naive solution: I just let each thread to process Length / num_threads of records. Only the last thread will process length/num_threads + length%num_threads records.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM