【问题标题】:Java HashTable ConcurrencyJava HashTable 并发
【发布时间】:2012-07-27 11:43:16
【问题描述】:

我有一个 Java 代码,它通过以下方式在哈希表中搜索值:

class HTDemo {
    public static void main(String args[]) {
        Hashtable balance = new Hashtable();
        double bal;
        balance.put("John Doe", new Double(3434.34));
        balance.put("Tom Smith", new Double(123.22));
        balance.put("Jane Baker", new Double(1378.00));
        balance.put("Todd Hall", new Double(99.22));
        balance.put("Ralph Smith", new Double(-19.08));

        **System.out.println("John Doe's balance: " + balance.get("John Doe"));**
        **System.out.println("Tom Smith's balance: " + balance.get("Tom Smith"));**
        **System.out.println("Jane Baker's balance: " + balance.get("Jane Baker"));**
    }
 }

现在,我想在多个线程上运行它,即我想以这样的方式修改代码,以便 get 方法(在 ** 内)同时工作。任何人都可以帮助我如何做到这一点。实际上,我遇到了传递哈希表并使其在运行时并发的问题。

【问题讨论】:

  • 您的问题是“如何创建新线程?”或“如何安全地处理对共享数据的多线程访问?”
  • @DNA,第二个。我想知道如何修改该代码以安全地处理它。
  • 你的问题不够精确。如果你在一个线程中填充地图,然后启动只从地图中读取的线程,你不需要做任何事情。如果您以读写方式访问它并且一次只对单个条目感兴趣,因为 Hashtable 是同步的,您不需要做任何事情。在其他情况下(例如原子地添加或获取两个条目,则需要特殊同步。您的问题太模糊而无法回答。

标签: java multithreading concurrency hashtable


【解决方案1】:

看看ConcurrentHashMap

...

支持检索的完全并发和可调整的预期更新并发的哈希表。

...

要并行化这三行,你可以简单地做

String[] users = { "John Doe", "Tom Smith", "Jane Baker" };
for (final String user : users) {
    new Thread() {
        public void run() {
            System.out.println(user + "'s balance: " + balance.get(user));
        }
    }.start();
}

如果您实际上有一个稍微复杂的场景,我建议您查看ExecutorService 和相关类。

【讨论】:

    【解决方案2】:

    你不能。 HashTable 的所有方法都是同步的。请参阅 Javadoc。使用 HashMap,或者,如果您需要线程 安全, 您没有提到,ConcurrentHashMap。

    【讨论】:

      【解决方案3】:

      Hashtable 是同步的,因此已经是线程安全的。在多线程环境中,您无需任何其他东西即可安全地访问您的代码。

      但是,HashTable 已经过时了,由于实现了线程安全机制(所有方法都是同步的)并且提供的迭代器不是线程安全的,并且如果您修改它会失败,因此它在高并发环境中的性能会很差迭代时的表。

      底线:使用 ConcurrentHashMap,并尽可能使用泛型:

      Map<String, Double> balance = new ConcurrentHashMap<String, Double> ();
      

      其余代码应保持不变。

      您还需要记住的一件事是,即使使用线程安全的数据结构(无论是 HashTable 还是 ConcurrentMap),您仍然需要处理诸如 atiomcity 之类的并发问题。

      例如,如果您检查余额以授权这样的付款:

      double johnBalance = balance.get("John");
      if(johnBalance > paymentAmount) 
          authorisePayment();
      else
          declinePayment();
      

      存在原子性问题:John 帐户上的余额可能在调用 balance.get(...) 和支付授权之间发生了变化。

      如果这是您的用例之一,您将需要引入额外的同步层。

      【讨论】:

      • 即使是 ConcurrentHashMap 也不一定能神奇地保证一切安全和正确。例如,如果必须以原子方式存储或检索映射中的两个条目,则仍然需要外部同步。
      • @JBNizet 当然 - 阅读这个问题,我认为原子性不是必需的,但我会相应地进行编辑。
      • @JBNizet 希望这是一个练习 - 如果不是,我想知道银行的名称 ;-)
      • 我也有同样的印象,但不是 100% 确定。你回答的结论让我有点害怕。也许是我,但我将其解读为:使用 ConcurrentHashMap,无论您在其余代码中做什么,它都是正确的。 +1,不过。
      • @JBNizet 这是一个中肯的评论。
      【解决方案4】:

      也许您在 hashmap 上使用 Hashtable 是因为您想要访问您的多线程环境。好吧,这些同步集合现在已经过时了,因为它们确实不能解决同步问题。他们实际上已经雾化了添加或删除。 但他们没有解决一个简单的场景,即在 map 中您需要先检查密钥是否存在,然后再添加。

      Collection.synchronozimap() 在解决并发问题方面领先一步。但它们在密集的多线程环境中也失败了。

      最终首选的方法是使用并发 API。他们通过 ConcurrentMap.putIfAbsent 方法解决了我上面描述的一些问题。

      【讨论】:

      • Collections.synchronizedMap() 不是“领先一步”。这是一种从 HashMap 获得与 HashSet 完全相同的行为的方法。它什么也没增加。没有进展:没有领先一步。
      • whhhhhhhhhaaatt..!!!!与 HashMap 中的 HashSet 完全相同的行为。 ??????//.....你能引用一些参考吗?.
      • 错误,Javadoc?你能引用一些“领先一步”的参考吗?并给出一个例子'step'?
      猜你喜欢
      • 2010-11-15
      • 2019-05-02
      • 2011-01-04
      • 2011-05-25
      • 2011-06-05
      • 2015-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多