2010-05-19 47 views
7

所以我想有一个存储一系列股票报价的arraylist。但我保持跟踪竞标价格,询问每个价格和最后价格。同步读取到一个java集合

当然在任何时候,出价询问或给定股票的最后一个可以改变。

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

我想确保在阅读时没有其他线程正在更新价格。所以我看着同步收集。但这似乎只阻止阅读,而另一个线程添加或删除一个条目到数组列表。

所以现在我到包装方式:

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的内容 - 在同一时间。我正在处理这个权利?

谢谢。

+0

您是否试图防止写入同时发生的读取引用对象?如果是这样,锁定集合将无法完成此操作。看到我的答案。 – DJClayworth 2010-05-19 13:48:34

回答

0

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

看着你的代码,但我不相信你有一个重大的同步问题。如果您尝试在写作的同时进行阅读,您可以先取得价格或写入后的价格。如果你不知道写作将会发生,那对你无关紧要。你可以在一个较高的水平需要锁定,这样

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

发生作为一个原子操作,你最终不会在5.0,而不是10.0畅销。

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

+0

谢谢你让我觉得我需要更清楚地说明要锁定什么。将数小时面条上。 – jeff 2010-05-19 16:52:06

+0

DJ - 另外,我想我现在已经陷入了困惑,试图去思考这个问题。我正在看你在上面以粗体写出的内容....锁定集合并将其标记为最终的区别是什么?我认为把它标记为最终是防止地图上的哪些对象发生变化。 – jeff 2010-05-20 01:17:45

+0

@Jeff final只声明变量为“不可变”,而不是变量上的对象。所以名单仍然是可变的。如果你想列表是不可变的,请参阅'Collections.unmodifiableList()' – Hardcoded 2010-05-20 07:12:46

1

是的,这会的工作,反正你也不需要自己做,因为它是在集合框架

Collections.synchronizedList

+1

同步列表将不起作用,因为他更新该同步块中列表的条目属性。 – Hardcoded 2010-05-19 07:44:03

1

这看起来像一个合理的做法已经实施。吹毛求疵的,不过,你可能不应该包括在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; 
} 

我不知道,如果这只是我的口味还是有一些涉及并发性疑难杂症,但它至少看起来比较干净;-)。

2

是的,你是在正确的轨道上,这应该工作。

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

+2

哈希表(和向量)在JDK 1.2之前,应该避免。相反,考虑Collections.synchronizedMap(Map m)来创建一个线程安全的HashMap。另外,尽管OP没有明确说明,但我怀疑报价需要按照典型的订单进行排序。 – Adamski 2010-05-19 08:05:52

1

你的方法应该做的伎俩,但正如你所说,一次只能有一个读者和作家。这不是很有规模。

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

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

编辑:
假设您需要订购你的地图,看看在ConcurrentNavigableMap接口。

1

你有什么工作,但是每当你想要读取或更新元素的值时锁定整个列表是不可缩放的。如果这并不重要,那么你对所拥有的就没有问题。如果您想使其更具可扩展性,请考虑以下事项...

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

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

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

+0

看起来似乎是一个更有意义的hashmap。我可能默认列出太多而不想。 单个Qte对象上的不可变事物可能会帮助解决部分问题。但我需要多做点工作才能理解它。什么是使Qte对象不可变的语法,或者我将搜索。另外,不可变意味着“改变”我需要重新分配它的对象? (我正在查看响应中的文本,“要更新,只需使用the_list [i] = new Qte(...)” – jeff 2010-05-19 16:48:47

+0

不可变意味着“不能改变”。例如,Strings是不可变的,而StringBuffers是你不能改变一个String对象的值(例如,你不能说String s =“a”; s.append(“b”);。 一个不可变的Qte类会有出价,ask价格和最后价格作为最终成员变量,这3个值将被传递给构造函数。成员变量可以是公共的,或者每个成员变量都可以有一个getter(但不包括setter) – Angus 2010-05-21 15:39:36

+0

另外,关于DJClayworth的评论“在写入之前获得价格或价格之后的价格“,这只有在Qte.bid是32位(或更少)值或易失性时才为真。对于64位非易失性值,可以在写入过程中读取并获取错误数据(有关详细信息,请参阅Java语言规范,第17.7节),因此您需要将Qte.bid更改为float或int或让它成为双精度并声明它是不稳定的(如果它不是)。完成之后,您可以安全地读取和写入q.bid而无需同步。 (你可以忽略我的不变性建议) – Angus 2010-05-21 15:50:39