将读取同步到java集合

时间:2010-05-19 06:08:00

标签: java thread-safety

所以我希望有一个存储一系列股票报价的arraylist。但我会跟踪每个的出价,要价和最后价格。

当然,任何时候,特定股票的买入价或最后价格都可能发生变化。

我有一个更新价格的线程和一个读取它们的线程。

我想确保在阅读时没有其他线程正在更新价格。所以我看了同步集合。但这似乎只是在另一个线程添加或删除arraylist的条目时阻止了阅读。

所以现在我采用了包装器方法:

public class Qte_List {
private final ArrayList<Qte> the_list;

public void UpdateBid(String p_sym, double p_bid){
    synchronized (the_list){
        Qte q = Qte.FindBySym(the_list, p_sym);
        q.bid=p_bid;}
}

public double ReadBid(String p_sym){
    synchronized (the_list){
        Qte q = Qte.FindBySym(the_list, p_sym);
        return q.bid;}
}

所以我想用这个完成的只有一个线程可以做任何事情 - 一次读取或更新the_list的内容。我接近这个吗?

感谢。

6 个答案:

答案 0 :(得分:3)

是的,你走在正确的轨道上,这应该有效。

但为什么不使用已同步的现有Hashtable集合,并提供键值查找?

答案 1 :(得分:1)

是的,这将有效,无论如何你不需要自己做,因为它已经在集合框架中实现

Collections.synchronizedList

答案 2 :(得分:1)

这看起来像是一种合理的方法。但是,在Nit-picking中,您可能不应该在synchronized块中包含return语句:

public double ReadBid(String p_sym){
    double bid;
    synchronized (the_list) {
        Qte q = Qte.FindBySym(the_list, p_sym);
        bid = q.bid;
    }

    return bid;
}

我不确定这只是我的口味还是涉及到一些并发问题,但至少它对我来说看起来比较干净; - )。

答案 3 :(得分:1)

你的方法应该可以解决问题,但正如你所说,一次只能有一个读者和作者。这不是很容易扩展。

有一些方法可以在不失去线程安全性的情况下提高性能 例如,您可以使用ReadWriteLock。这将允许一次多个读者,但是当有人获得写锁定时,所有其他人必须等待他完成。

另一种方法是使用适当的集合。您似乎可以使用Map的线程安全实现来交换列表。查看ConcurrentMap documentation可能的候选人。

修改
假设您需要为地图订购,请查看ConcurrentNavigableMap界面。

答案 4 :(得分:1)

您所拥有的功能,但每次要读取或更新元素值时锁定整个列表都是不可扩展的。如果这无关紧要,那么你对自己所拥有的一切都很好。如果您想让它更具可扩展性,请考虑以下内容......

您没有说明是否需要对the_list进行结构更改(添加或删除元素),但如果不这样做,一个重大改进就是将调用移到FindBySym()之外同步块。然后,您可以只在q(Qte对象)上进行同步,而不是在the_list上进行同步。这样,您可以同时更新不同的Qte对象。此外,如果您可以使Qte对象也不可变,则实际上根本不需要任何同步。 (要更新,只需使用the_list [i] = new Qte(...))。

如果您确实需要对列表进行结构更改,可以使用ReentrantReadWriteLock来允许并发读取和独占写入。

我也很好奇你为什么要使用ArrayList而不是同步的HashMap。

答案 5 :(得分:1)

据我所知,你正在用地图存储报价;报价数量永远不会改变,但每个报价都可以被读取或修改以反映当前价格。 重要的是要知道锁定集合只能防止更改Quote对象在地图中的位置:它不会以任何方式限制对这些行情内容的修改。如果要限制该访问权限必须在Quote对象上提供锁定。

查看您的代码,但我不相信您有严重的同步问题。如果您尝试在写入的同时进行读取,您将获得之前的价格或写入之后的价格。如果您不知道写入将要发生,那对您来说无关紧要。您可能需要锁定更高级别以便

if (getBidPrice(mystock)<10.0) {
  sell(10000);
}

作为原子操作发生,并且最终不会以5.0而不是10.0来销售。

如果引号的数量确实没有改变,那么我建议只允许在Qte_List的构造函数中添加Qte对象。这将使锁定集合无关紧要。技术术语是使Qte_List 不可变