2

我有一个 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 方法(在**内部)同时工作。任何人都可以帮助我如何做到这一点。实际上,我遇到了传递哈希表并在运行时使其并发的问题。

4

4 回答 4

6

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(...)和付款授权之间发生了变化。

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

于 2012-07-29T16:37:09.803 回答
2

看看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相关类。

于 2012-07-29T16:17:32.897 回答
2

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

于 2012-07-29T16:19:28.680 回答
2

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

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

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

于 2012-07-29T16:39:03.017 回答