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

发布于 2024-11-01 19:36:50 字数 1986 浏览 5 评论 0原文

我正在使用java创建一个网络管理应用程序。在此应用程序中,我使用 SNMP4j 库(用于 snmp 协议)与网络设备建立通信。因此,我应该使用此协议扫描网络设备的某些值并将结果放入文件中进行缓存。在某些时候,我决定使我的应用程序成为多线程并将设备分配给线程。我创建了一个实现可运行接口的类,然后扫描我想要为每个设备提供的值。

当我单独运行这门课时,效果很好。但是当我同时放置多个线程时,输出会变得混乱,它会将额外的或无序的输出打印到文件中。现在,我想知道这个问题是由于 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 = 管理员

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 = 管理

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));
        } 

I am using java to create an application for network management. In this application I establish communication with network devices using SNMP4j library (for the snmp protocol). So, Im supposed to scan certain values of the network devices using this protocol and put the result into a file for caching. Up in some point I decided to make my application multi-threaded and assign a device to a thread. I created a class that implements the runnable interface and then scans for the values that I want for each device.

When i run this class alone it, works fine. but when I put multiple threads at the same time the output mess up, it prints additional or out of order output into the files. Now, i wonder if this problem is due to the I/O or due to the communication.

Here I'll put some of the code so that you can see what im doing and help me figure what's wrong.

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();
//...
   }

}

some of the expected ooutput would be something like:

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 days, 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 = Computer Room

but instead i get something like (varies):

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 days, 22:35:02.31

1.3.6.1.2.1.1.6.0 = Computer Room

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

*Currently I have one file per device scanner desired.
i get them from a list of ip , it looks like this. Im also using a little threadpool to keep a limited number of threads at the same time .


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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

水溶 2024-11-08 19:36:50

我怀疑 SNMPV1Communicator(device) 不是线程安全的。正如我所看到的,它不是 SNMP4j 库的一部分。

I suspect SNMPV1Communicator(device) is not thread-safe. As I can see it's not a part of SNMP4j library.

只有影子陪我不离不弃 2024-11-08 19:36:50

疯狂猜测这里发生了什么,尝试将所有内容放入 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 的缓冲区已满时,它本质上是随机的 - 它很可能位于一行的中间。

上面的同步块意味着一次只能有一个线程写入该线程的 OutputStreamWriter。末尾的 flush() 意味着在离开同步块之前,OutputStreamWriter 的缓冲区应该已刷新到底层 OutputStream

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

Taking a wild guess at what's going on here, try putting everything inside a synchronized() block, like this:

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

        }
        out.flush();
 }

If this works, my guess is right and the reason for the problems you're seeing is that you have many OutputStreamWriters (one on each thread), all writing to a single OutputStream. Each OutputStreamWriter has its own buffer. When this buffer is full, it passes the data to the OutputStream. It's essentially random when each each OutputStreamWriter's buffer is full - it might well be in the middle of a line.

The synchronized block above means that only one thread at a time can be writing to that thread's OutputStreamWriter. The flush() at the end means that before leaving the synchronized block, the OutputStreamWriter's buffer should have been flushed to the underlying OutputStream.

Note that synchronizing in this way on the class object isn't what I'd consider best practice. You should probably be looking at using a single instance of some other kind of stream class - or something like a LinkedBlockingQueue, with all of the SNMP threads passing their data over to a single file-writing thread. I've added the synchronized as above because it was the only thing available to synchronize on within your pasted example code.

苹果你个爱泡泡 2024-11-08 19:36:50

您有多个线程,所有线程都使用缓冲输出,并且指向同一个文件。

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

You've got multiple threads all using buffered output, and to the same file.

There's no guarantees as to when those threads will be scheduled to run ... the output will be fairly random ordered, dictated by the thread scheduling.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文