Java(基本)多线程与Hashmap问题

时间:2015-04-16 15:47:40

标签: java multithreading hashmap

我正在研究如何进行多线程,主要来自这个网站:http://www.tutorialspoint.com/java/java_multithreading.htm

我试图将它实现到我自己的Hash Map Implementation中。我的想法是,当我重新调整我的hashmap大小时,我可以使用多线程,这样当它在较大的哈希映射的条目中添加时,我可以使用另一个线程将较小的哈希映射重新哈希到较大的哈希映射中。

我对Hash Map的实现工作正常 - 但是我很难掌握多线程,所以我想知道是否有人可以查看我的代码,看看我哪里出错了?

public class HashMap extends Thread
{
  private Thread t;
  private String threadName;
  private long noofitems;
  private HashPair[] data;
  HashPair[] newArray;

  private int copyCounter = 0;

  public HashMap(int initlen)
  {
    noofitems=0;
    data=new HashPair[initlen];
    threadName = "t1";
  }

  public void run()
  {
      for (int i = 0; i < 5 && copyCounter < noofitems; i++)
            {
               if (data[copyCounter] != null)
               {
                    int test1=HashFunction(data[copyCounter].key);
//                    newArray[test1] = data[copyCounter];                     
                    int index = test1 % newArray.length;
                    boolean tempInserted = false;
                    int tempIncrement = 1;
                    while (!tempInserted)
                    {            
                        if (newArray[index] == null)
                        {
                            newArray[index] = data[copyCounter];
                            noofitems++;
                            System.out.println("Thread Added");
                            tempInserted = true;
                        }

                    }
                    copyCounter++;
               }
               else
               {
                   copyCounter++;
               }                               
            }
  }

  //make data point to newArray
  //null newArray
  //if copyCounter >= data.length { do null thing}
  public void AddItem(String key, String value)
  {
//    System.out.println("Adding: "+key+" "+value);
    int index=HashFunction(key);
    //++hits[index%data.length];

    HashPair item=new HashPair(key, value);

    // Task 3: Check load factor here and resize if over 0.7
        if ((noofitems/(float)data.length) > 0.7 && newArray == null)
        {
            newArray = new HashPair[data.length*2];   
            //copyCounter = 0;
        }    


    // Task 2 Code: Insert item into the data, but check and resolve collisions first
    // When you have this, implement the GetValue method
        if (newArray == null)
        {
            index = index % data.length;
            boolean inserted = false;
            int increment = 1;
            while (!inserted)
            {            
                if (data[index] == null)
                {
                    data[index] = item;
                    noofitems++;
                    inserted = true;
                }


            }  
        }
        else
        {
            if (t == null)
            {
                t = new Thread(this, threadName);
                t.start();
            }

            index = index % newArray.length;
            boolean inserted = false;
            int increment = 1;
            while (!inserted)
            {   
                if (index < 0)
                    System.out.println();
                if (newArray[index] == null)
                {
                    newArray[index] = item;
                    noofitems++;
                    inserted = true;
                }

            }

        }       
  }

  private int HashFunction(String key)
  {
    // Task 1 code: Hash the key and return a long value
    int code = 38;     
    for (int i=0; i < key.length(); i++) 
    {
        code = code*3+(key.charAt(i));
    }
    return (code>0?code:-code);
  }

目前我已将其设置为将5个小哈希映射条目一次复制到较大的哈希映射中 - 无论如何考虑,一次最多复制一个哈希映射可能会更好?否则主线程将空闲,而第二个线程完成复制剩余的4个跨越?

我在尝试执行程序时遇到此错误:

Thread Added
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1583
at hashmaps.HashMap.AddItem(HashMap.java:119)
at hashmaps.Dictionary.CreateDictionary(Dictionary.java:71)
at hashmaps.Dictionary.main(Dictionary.java:15)

Java结果:1

第119行= if(newArray [index] == null)

1 个答案:

答案 0 :(得分:3)

查看HashFunction方法的结尾:

return (code>0?code:-code);

如果您的计算code恰好具有值Integer.MIN_VALUE,则没有int值来表示-Integer.MIN_VALUE并且会发生数值溢出,结果仍为负数Integer.MIN_VALUE

如果您使用了Math.abs(…),那么阅读its documentation已经指向了正确的方向:

  

请注意,如果参数等于Integer.MIN_VALUE的值,即最负的可表示的int值,则结果是相同的值,即负值。

如果HashFunction的结果可能为否定,则index % data.length的结果也可能为负数,这说明了如何收到ArrayIndexOutOfBoundsException报告否定索引。


请注意,这与多线程无关。我不认为您已准备好实现多线程代码。并不是说你没有使你的代码线程安全,没有丝毫尝试这样做。因此,只要您没有了解线程安全构造的必要性,就应该继续学习本教程,而不是尝试实现操作共享数据的并发代码。


此外,我不确定您是否理解代码的含义,例如:当你使用

tempIncrement++;
index = index + (tempIncrement<<1);
index = index % newArray.length;

运算符++将变量递增1,而操作<<1相当于将int值加倍。换句话说,你基本上是通过增加的偶数数进行迭代,并且由于你的数组大小在每次容量增加时加倍,你的迭代只能达到一半数组条目,可以是所有偶数或所有奇数条目,具体取决于它开始的索引。

更糟糕的是,由于你增加了增量,你正在跳过越来越多的条目,直到你的增量大于数组本身,因此你将重复检查相同的条目,增量没有效果。

因此,根据您的hashmap的填充状态,您在这里玩俄语轮盘赌,在搜索免费(无 - null)条目时冒着无限循环的风险。


您应该注意的另一件事是您正在根据精确的char值计算哈希码,但将其与使用compareToIgnoreCase组合以确定两个键是否相等。您应该决定是否要匹配不区分大小写,在这种情况下,您必须调整哈希代码计算,或者您希望进行完全匹配,在这种情况下,您不应该使用compareToIgnoreCase,而只需equals 1}}(你可以使用compareTo但是当你只需要一个相等的测试时没有理由这样做。否则,这种不一致迟早会适得其反......