java - 如何多次实例化一个实现可运行并打开套接字的类?

标签 java multithreading sockets runnable

我正在开发一个项目,其中有一个类 DeviceCommunicator,它实现了 Runnable。目前,主类实例化 DeviceCommunicator 的单个实例,该实例(最终)使用 Socket 库连接到本地网络上的设备。

最终,我的意思是,如果需要发送消息,则 DeviceCommunicator 的实例将打开与设备的套接字连接,发送消息,然后启动一个新的消息。线程通过以下代码行从套接字接收返回的数据:

new Thread(new DeviceCommunicator()).start();

编辑:澄清一下,这是程序执行时的操作顺序:

1) MAIN 类实例化一个带有构造函数的 DeviceCommunicator 类,例如:

comm1 = DeviceCommunicator(主机名, 端口号)

2) MAIN 类想要向 comm1 发送消息,因此它调用 send,如下所示:

comm1.send(someString)

3) comm1 的类型为 DeviceCommunicator,并打开与 hostName/portNum 的 Socket 连接,如下所示:

deviceSocket = new Socket(hostName, portNum);
out = new PrintStream(deviceSocket.getOutputStream());
in = new BufferedReader(new InputStreamReader(deviceSocket.getInputStream()));

4) comm1 将 someStr 发送到输出 PrintStream,然后使用以下代码初始化一个线程来监听响应:

new Thread(new DeviceCommunicator()).start();

由于监听 DeviceCommunicator 线程没有构造函数参数,因此需要我制作输出 PrintStream 和输入 BufferedReader > 静态变量。

当我只有一个 DeviceCommunicator 实例时 - 这非常有用!

但是,我想要 DeviceCommunicator 类的多个实例可以连接到本地网络上的相同或不同设备,但是考虑到以下事实: DeviceCommunicator 类中的输出和输入是static,然后它们是共享的(我认为,我读过 JVM 并不能完全保证静态变量的更改会被共享)在 DeviceCommunicator 的所有实例中对其他正在运行的线程可见) - 这是一个问题!

我做了一些研究,但没有遇到过类似的主题 - 大多数主题基本上都是“非此即彼”,其中:

A) 主题是关于线程套接字通信,其中“非阻塞”通信是通过使用静态变量来完成的。

B) 考虑一种简单的实现 Runnable 情况,其中一个线程将完成一个(通常是简单的)任务,而另一个线程将完成另一项(通常稍作修改的)任务。

编辑:我想可能提出的一个解决方案是简单地将输入 BufferedReader 传递到监听 DeviceCommunicator 线程,但是我正在实现一个消息队列发送(如果出现网络问题);因此,如果需要发送消息,它只需获取队列中的第一个元素并将其打印到套接字连接,我想在监听线程中验证设备是否正确接收该消息。如果消息被正确接收,那么我想从队列中删除该元素,但是这又带来了一个问题 - 在 Java 中传递变量总是按值传递,而不是按引用传递!因此,如果我要传递输入 BufferedReader 队列,则在监听 DeviceCommunicator 中修改的队列将不是实际的队列需要在主 DeviceCommunicator 实例中修改的队列。

是否有一个我不知道的明显解决方案?

提前致谢!

最佳答案

如果您可以控制 DeviceCommunicator 类,我会将您需要的 StreamReader 对象作为参数传递给构造函数。我当然不会以这种方式使用静态变量。

new Thread(new DeviceCommunicator(hostName, portNum, in, out)).start();

现在,如果多个线程正在读取和写入流,那么您必须在执行此操作之前对它们进行同步。

您还在评论中提到,您需要有一个队列来发送消息。这也可能是 DeviceCommunicator 的一个参数,尽管您需要将其设置为同步列表或其他内容:

List<String> toSendList = Collections.synchronizedList(new ArrayList<String>());
...
new Thread(new DeviceCommunicator(hostName, portNum, in, out, toSendList)).start();

但是,更好的模式是在 DeviceCommunicator 上添加一个 send 方法,该方法会将项目添加到队列中,而不是同时添加到主线程和发送线程中具有相同的队列。如果您向 DeviceCommunicator 添加方法,您也许还可以让它隐藏读取器和写入器流,并且主线程不会直接访问流。 Data hiding是面向对象程序的重要特性之一。

关于java - 如何多次实例化一个实现可运行并打开套接字的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10336606/

相关文章:

java - Jackson 通过特定键将 json 反序列化为不同的子类

java - 服务器/客户端停止 1 个线程 = 1 个客户端

multithreading - Windows 和 Solaris 10 上的 std::async 性能

sockets - 如何在 Dart 中通过套接字发送文件

java - java.net.SocketException : Connection reset and java.net.SocketException : Broken Pipe? 有什么区别

delphi - TTcpClient/TTcpServer 和 TClientSocket/TServerSocket 有什么区别?

java - Android应用程序远程连接到数据库

java - 有没有更好的方法将日历日期归零?

java - CGLIB 可以在 Android 上使用吗?

c++ - 线程间同一个socket的recv/send/close代码需要加锁吗