Java LinkedBlockingQueue和工作线程-此代码是线程安全的吗?

Java LinkedBlockingQueue和工作线程-此代码是线程安全的吗?,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,我试图理解下面的代码是否是线程安全的,它是由另一个开发人员编写的,我继承了他的代码,现在已经不在我们身边了 我有一个BaseProvider类,它实际上是一个消息缓存,由LinkedBlockingQueue表示。此类在队列中存储传入消息 我有一组工作线程读取这个队列的数据。因此,LinkedBlockingQueue是线程安全的 问题 1.当工作线程调用provider.getnextqueeditem()时,提供程序逐项检查并将其添加到列表中,然后返回消息列表。执行此操作时,如果通过调用ad

我试图理解下面的代码是否是线程安全的,它是由另一个开发人员编写的,我继承了他的代码,现在已经不在我们身边了

我有一个BaseProvider类,它实际上是一个消息缓存,由LinkedBlockingQueue表示。此类在队列中存储传入消息

我有一组工作线程读取这个队列的数据。因此,LinkedBlockingQueue是线程安全的

问题 1.当工作线程调用provider.getnextqueeditem()时,提供程序逐项检查并将其添加到列表中,然后返回消息列表。执行此操作时,如果通过调用addToQueue将消息添加到提供程序类中,会发生什么情况?LinkedBlockingQueue内部的takeLock是否阻止向队列添加新消息,直到所有消息都从队列中删除

  • 正如您所注意到的,每个工作线程都可以访问所有提供程序,因此当一个工作线程遍历所有提供程序并调用GetNextQueedItem()时,当另一个工作线程也遍历所有提供程序并调用GetNextQueedItem()时会发生什么情况?两个工作线程是否会相互重叠

    公共抽象类BaseProvider实现IProvider{

     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,“…这将使第二条消息在第一条消息确认之前保持在队列中吗