Java LinkedBlockingQueue和工作线程-此代码是线程安全的吗?
我试图理解下面的代码是否是线程安全的,它是由另一个开发人员编写的,我继承了他的代码,现在已经不在我们身边了 我有一个BaseProvider类,它实际上是一个消息缓存,由LinkedBlockingQueue表示。此类在队列中存储传入消息 我有一组工作线程读取这个队列的数据。因此,LinkedBlockingQueue是线程安全的 问题 1.当工作线程调用provider.getnextqueeditem()时,提供程序逐项检查并将其添加到列表中,然后返回消息列表。执行此操作时,如果通过调用addToQueue将消息添加到提供程序类中,会发生什么情况?LinkedBlockingQueue内部的takeLock是否阻止向队列添加新消息,直到所有消息都从队列中删除Java LinkedBlockingQueue和工作线程-此代码是线程安全的吗?,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,我试图理解下面的代码是否是线程安全的,它是由另一个开发人员编写的,我继承了他的代码,现在已经不在我们身边了 我有一个BaseProvider类,它实际上是一个消息缓存,由LinkedBlockingQueue表示。此类在队列中存储传入消息 我有一组工作线程读取这个队列的数据。因此,LinkedBlockingQueue是线程安全的 问题 1.当工作线程调用provider.getnextqueeditem()时,提供程序逐项检查并将其添加到列表中,然后返回消息列表。执行此操作时,如果通过调用ad
private LinkedBlockingQueue<CoreMessage> internalQueue = new LinkedBlockingQueue<CoreMessage>();
@Override
public synchronized List<CoreMessage> getNextQueuedItem() {
List<CoreMessage> arrMessages = new ArrayList<CoreMessage>();
if (internalQueue.size() > 0) {
Logger.debug("Queue has entries");
CoreMessage msg = null;
try {
msg = internalQueue.take();
} catch (InterruptedException e) {
Logger.warn("Interruption");
e.printStackTrace();
}
if (msg != null) {
arrMessages.add(msg);
}
}
return arrMessages;
}
protected synchronized void addToQueue(CoreMessage message) {
try {
internalQueue.put(message);
} catch (InterruptedException e) {
Logger.error("Exception adding message to queue " + message);
}
}
private LinkedBlockingQueue internalQueue=new LinkedBlockingQueue();
@凌驾
公共同步列表getnextqueeditem(){
List arrMessages=new ArrayList();
if(internalQueue.size()>0){
debug(“队列有条目”);
CoreMessage msg=null;
试一试{
msg=internalQueue.take();
}捕捉(中断异常e){
记录器。警告(“中断”);
e、 printStackTrace();
}
如果(msg!=null){
arrMessages.add(msg);
}
}
返回消息;
}
受保护的同步void addToQueue(CoreMessage消息){
试一试{
internalQueue.put(消息);
}捕捉(中断异常e){
Logger.error(“将消息添加到队列中的异常”+消息);
}
}
}public class Worker implements Runnable
@Override
public void run() {
Logger.info("Worker - Running Thread : " + Thread.currentThread().getName());
while (!stopRequested) {
boolean processedMessage = false;
for (IProvider provider : providers) {
List<CoreMessage> messages = provider.getNextQueuedItem();
if (messages == null || messages.size() != 0) {
processedMessage = true;
for (CoreMessage message : messages) {
final Message msg = createEndurMessage(provider, message);
processMessage(msg);
message.commit();
}
}
}
if (!(processedMessage || stopRequested)) {
// this is to stop the thread from spinning when there are no messages
try {
Thread.sleep(WAIT_INTERVAL);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
公共类工作程序实现可运行
@凌驾
公开募捐{
info(“工作线程:+Thread.currentThread().getName());
而(!stopRequested){
布尔processedMessage=false;
对于(IProvider提供程序:提供程序){
List messages=provider.getnextqueeditem();
if(messages==null | | messages.size()!=0){
processedMessage=true;
用于(CoreMessage消息:消息){
最终消息msg=createEndurMessage(提供者,消息);
处理消息(msg);
message.commit();
}
}
}
如果(!(processedMessage | | stopRequested)){
//这是为了在没有消息时阻止线程旋转
试一试{
线程睡眠(等待间隔);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
}
}
如果通过调用addToQueue将消息添加到提供程序类中,会发生什么情况
getnextqueeditem()
和addToQueue(…)
都是同步的方法。如果只有这两种方法可以访问private。。。internalQueue
,则多个线程无法同时访问internalQueue
当一个工作线程遍历所有提供程序并调用GetNextQueedItem()时,当另一个工作线程也遍历所有提供程序并调用GetNextQueedItem()时会发生什么情况
您是否询问多个工作人员访问同一提供商?这不会发生,因为getnextqueeditem()
是一个同步的方法
--或--
您是否询问不同的员工访问不同的供应商?这应该无关紧要(至少对于BaseProvider
类来说不重要),因为似乎没有任何方式可以将不同的对象彼此连接起来。出于好奇,为什么getnextqueeditem()
返回一个消息列表?为什么不简单地返回消息呢?Re,if(messages==null | | | messages.size()!=0).
不清楚作者在这里想说什么,但这并不重要,因为messages
永远不能null
:getnextqueitem()
方法总是返回一个列表,其中可能包含零项或一项。此外,可能没有理由显式测试消息列表的大小,因为(…)
的循环无论如何都要对其进行测试。Re“当工作线程调用provider.getnextqueeditem()
时,提供程序逐项执行…”这似乎不是真的。在您的示例中,getnextqueeditem()
的实现只从internalQueue
中获取一个项,然后返回封装在new ArrayList
中的单个项。感谢您的回复@solmon slow。我还有一个问题-message.commit();正在进程消息之后调用。现在,如果两个工作线程已从提供程序拾取消息,并且第一个工作线程正在花时间处理第一条消息,同时第二个工作线程已完成处理第二条消息并发送消息的ack。由于第一条消息尚未确认,而第二条消息已确认,这将使第二条消息在第一条消息确认之前保持在队列中。@serah,Re,“…这将使第二条消息在第一条消息确认之前保持在队列中吗