我正在开发一个项目,其中有一个类 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
类,我会将您需要的 Stream
或 Reader
对象作为参数传递给构造函数。我当然不会以这种方式使用静态
变量。
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/