Java多线程I / 0和通信问题

时间:2011-04-15 17:46:19

标签: java multithreading sockets io

我正在使用java创建一个网络管理应用程序。在此应用程序中,我使用SNMP4j库(用于snmp协议)与网络设备建立通信。所以,我应该使用这个协议扫描网络设备的某些值,并将结果放入一个文件进行缓存。在某些方面我决定使我的应用程序多线程并将一个设备分配给一个线程。我创建了一个实现runnable接口的类,然后扫描每个设备所需的值。

当我单独运行这个课程时,它运行正常。但是当我将多个线程同时输出混乱时,它会在文件中输出额外的或无序的输出。现在,我想知道这个问题是由于I / O还是由于通信造成的。

在这里,我将放置一些代码,以便您可以看到我在做什么并帮助我找出错误。

public class DeviceScanner implements Runnable{
private final SNMPCommunicator comm;
private OutputStreamWriter out;

public DeviceScanner(String ip, OutputStream output) throws IOException {
        this.device=ip;
        this.comm = new SNMPV1Communicator(device);

        oids=MIB2.ifTableHeaders;
        out = new OutputStreamWriter(output);

    }

@Override
    public void run(){
//Here I use the communicator to request for desired data goes something like ...
                String read=""
        for (int j=0; j<num; j++){

                read= comm.snmpGetNext(oids);
                out.write(read);
                this.updateHeaders(read);

            }
            out.flush();
//...
   }

}

一些预期的输出将是这样的:

1.3.6.1.2.1.1.1.0 = SmartSTACK ELS100-S24TX2M

1.3.6.1.2.1.1.2.0 = 1.3.6.1.4.1.52.3.9.1.10.7

1.3.6.1.2.1.1.3.0 = 26天,22:35:02.31

1.3.6.1.2.1.1.4.0 = admin

1.3.6.1.2.1.1.5.0 = els

1.3.6.1.2.1.1.6.0 =计算机房

但我会得到像(变化)的东西:

1.3.6.1.2.1.1.1.0 = SmartSTACK ELS100-S24TX2M

1.3.6.1.2.1.1.2.0 = 1.3.6.1.4.1.52.3.9.1.10.7

1.3.6.1.2.1.1.4.0 = admin

1.3.6.1.2.1.1.5.0 = els

1.3.6.1.2.1.1.3.0 = 26天,22:35:02.31

1.3.6.1.2.1.1.6.0 =计算机房

1.3.6.1.2.1.1.1.0 = SmartSTACK ELS100-S24TX2M

1.3.6.1.2.1.1.2.0 = 1.3.6.1.4.1.52.3.9.1.10.7

*目前,每台设备扫描仪需要一个文件。 我从ip列表中获取它们,它看起来像这样。我还使用一个小线程池同时保留有限数量的线程。


for (String s: ips){
            output= new FileOutputStream(new File(path+s));
            threadpool.add(new DeviceScanner(s, output));
        } 

3 个答案:

答案 0 :(得分:1)

我怀疑SNMPV1Communicator(设备)不是线程安全的。我可以看到它不是SNMP4j库的一部分。

答案 1 :(得分:1)

对这里发生的事情进行疯狂猜测,尝试将所有内容放在synchronized()块中,如下所示:

 synchronized (DeviceScanner.class)
 {
        for (int j=0; j<num; j++){
            read= comm.snmpGetNext(oids);
            out.write(read);
            this.updateHeaders(read);

        }
        out.flush();
 }

如果这样可行,我的猜测是正确的,你看到的问题的原因是你有很多OutputStreamWriter个(每个线程一个),都写入一个OutputStream。每个OutputStreamWriter都有自己的缓冲区。当此缓冲区已满时,它会将数据传递给OutputStream。当每个OutputStreamWriter的缓冲区都已满时,它基本上是随机的 - 它可能位于一条线的中间。

上面的synchronized块意味着一次只能有一个线程写入该线程的OutputStreamWriter。最后的flush()表示在离开同步块之前,OutputStreamWriter的缓冲区应该已刷新到基础OutputStream

请注意,以这种方式在类对象上进行同步并不是我认为的最佳实践。您可能应该考虑使用其他类型的流类的单个实例 - 或类似LinkedBlockingQueue的实例,所有SNMP线程将其数据传递到单个文件写入线程。我已经添加了如上所述的synchronized,因为它是唯一可用于在粘贴的示例代码中进行同步的内容。

答案 2 :(得分:0)

你有多个线程都使用缓冲输出,并使用相同的文件。

无法保证何时将调度这些线程运行...输出将是相当随机的,由线程调度决定。