我可以从并发线程调用XMPPConnection.sendPacket吗?

时间:2009-09-18 08:20:25

标签: java multithreading concurrency xmpp smack

动机

我希望额外的目光确认我能够调用此方法 XMPPConnection.sendPacket( 数据包)同时发生。对于我当前的代码,我以串行方式调用Callables列表(最多3个)。每个Callable在一个XMPPConnection上发送/接收XMPP数据包。我计划通过分离多个线程和&来并行化这些Callables。每个Callable都将在共享的XMPPConnection上调用sendPacket而不进行同步。

XMPPConnection

class XMPPConnection
{
    private boolean connected = false;

    public boolean isConnected() 
    {
        return connected;
    }

    PacketWriter packetWriter;

    public void sendPacket( Packet packet ) 
    {
        if (!isConnected())
            throw new IllegalStateException("Not connected to server.");

        if (packet == null) 
            throw new NullPointerException("Packet is null.");

        packetWriter.sendPacket(packet);
    }
}

PacketWriter

class PacketWriter
{
    public void sendPacket(Packet packet) 
    {
        if (!done) {
            // Invoke interceptors for the new packet 
            // that is about to be sent. Interceptors
            // may modify the content of the packet.
            processInterceptors(packet);

            try {
                queue.put(packet);
            }
            catch (InterruptedException ie) {
                ie.printStackTrace();
                return;
            }
            synchronized (queue) {
                queue.notifyAll();
            }

            // Process packet writer listeners. Note that we're 
            // using the sending thread so it's expected that 
            // listeners are fast.
            processListeners(packet);
    }

    protected PacketWriter( XMPPConnection connection ) 
    {
        this.queue = new ArrayBlockingQueue<Packet>(500, true);
        this.connection = connection;
        init();
    }
}

我的结论

由于PacketWriter正在使用BlockingQueue,因此我打算从多个线程调用sendPacket没有问题。我是对的吗?

3 个答案:

答案 0 :(得分:2)

是的,您可以毫无问题地从不同的线程发送数据包。

Smack阻塞队列是因为你不能做的是让不同的线程同时写输出流。 Smack负责通过以每个数据包粒度写入来同步输出流。

Smack实现的模式只是一种典型的生产者/消费者并发模式。你可能有几个生产者(你的线程)和只有一个消费者(Smack的PacketWriter在它自己的线程中运行)。

问候。

答案 1 :(得分:0)

您在此处未提供足够的信息。

我们不知道如何实施以下内容:

  • processInterceptors
  • processListeners

谁读/写'完成'变量?如果一个线程将其设置为true,那么所有其他线程将无声地失败。

从快速浏览一下,这看起来并不安全,但是没有办法确定你发布的内容。

其他问题:

  • 为什么PacketWriter是XMPPConnection的类成员,它只在一个方法中使用?
  • 为什么PacketWriter有一个XMPPConnection成员var而不使用它?

答案 2 :(得分:0)

如果可以限制为Java 5 +,则可以考虑使用BlockingQueue。

从Java API文档中,稍作更改即可使用ArrayBlockingQueue:

class Producer implements Runnable {
   private final BlockingQueue queue;
   Producer(BlockingQueue q) { queue = q; }
   public void run() {
     try {
       while(true) { queue.put(produce()); }
     } catch (InterruptedException ex) { ... handle ...}
   }
   Object produce() { ... }
 }

 class Consumer implements Runnable {
   private final BlockingQueue queue;
   Consumer(BlockingQueue q) { queue = q; }
   public void run() {
     try {
       while(true) { consume(queue.take()); }
     } catch (InterruptedException ex) { ... handle ...}
   }
   void consume(Object x) { ... }
 }

 class Setup {
   void main() {
     BlockingQueue q = new ArrayBlockingQueue();
     Producer p = new Producer(q);
     Consumer c1 = new Consumer(q);
     Consumer c2 = new Consumer(q);
     new Thread(p).start();
     new Thread(c1).start();
     new Thread(c2).start();
   }
 }

对于您的使用,您的真实发件人(实际连接的持有者)是消费者,而数据包准备者/发件人是生产者。

另一个有趣的想法是,您可以使用PriorityBlockingQueue来允许闪存覆盖在任何其他等待数据包之前发送的XMPP数据包。

此外,格伦在设计上的观点是好点。您可能想要查看Smack API(http://www.igniterealtime.org/projects/smack/),而不是创建自己的。