2013-10-21 50 views
0

我想以线程安全的方式存储对象列表,同时保持优先级。本来我开始使用BlockingQueue,因为它是线程安全的,并且有能力维护自定义优先级。我是否需要将呼叫同步到BlockingQueue(java)?

我在想我是否需要同步我的方法?我的代码如下所示:

void addToQueue(SomeObject obj) { 
    ... put it on my priority queue 
    ... do some logging 
} 

我已经注意到的是记录正在发生失灵,从多个线程访问addToQueue时。所以我用这样的方法包装了我的方法:

void addToQueue(SomeObject obj) { 
    syncronized(myMutex) { 
     ... put it on my priority queue 
     ... do some logging 
    } 
} 

这似乎是为了保持记录的顺序。所以现在我得出结论,如果我要走这条路线,那么也许我的代码会更有效率,因为不使用BlockingQueue,而是使用Set或List并自己管理优先级。

也许我对BlockingQueue有一些误解。

+2

在'BlockingQueue'同步的唯一的事情就是在各个方法的代码的一部分。日志记录不是“BlockingQueue”的一部分,因此不会受其执行限制。 –

+0

这是一个对象集合吗?批量集合操作addAll,containsAll,retainAll和removeAll不一定以原子方式执行,除非在实现中另行指定。因此,例如,在添加c中的一些元素后,addAll(c)可能会失败(抛出异常)。 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html – JNL

+0

本质上,BlockingQueue具有阻塞操作,所以要小心在同步部分内进行阻塞调用代码,否则你可能会陷入僵局。 – jekennedy

回答

1

另外支持在检索元素时等待队列变为非空操作的队列,并且在存储元素时等待队列中的空间变得可用。

这是用于BlockingQueue的javadoc。如果你需要这种阻塞行为,你可以使用它,否则你不需要。

BlockingQueue确实不是保持任何优先级,这是严格先进先出。也许您正在使用PriorityBlockingQueue

来到你的伪代码:

void addToQueue(SomeObject obj) { 
    ... put it on my priority queue 
    ... do some logging 
} 

队列是线程安全的,但是,这只意味着多个线程可以同时调用put it on my priority queue数据没有遭到损坏。它不保证以下任何一项:

  • 如果有多个线程阻塞哪一个会成功的第一
  • 如果thread X完成putthread Y然后thread X还将thread Y前完成logging

如果你需要所有addToQueue发生没有从其他线程交错,那么你需要同步。请注意,您可以使用队列对象本身:

void addToQueue(SomeObject obj) { 
    synchronized (queue) { 
     ... put it on my priority queue 
     ... do some logging 
    } 
} 
0

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

与其他并发集合之前,在一个线程动作将对象放入到该元素的从BlockingQueue的另一线程中访问或移除之后的的BlockingQueue发生-之前的动作。

如果您想使用安全得到有序的记录,你必须登录之前把物品放入队列,并从队列中取出一个项目后

我不会使用​​来获得有序的日志记录。多线程意味着并行执行,这意味着某些操作没有排序。日志记录可以有一个时间戳,并以错误的顺序看到它们,即在控制台中,对我来说看起来像是一个小毛病,不值得牺牲并行执行的优点。