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

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

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

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

1)MAIN类实例化带有构造函数的DeviceCommunicator类,如下所示:
comm1 = DeviceCommunicator(hostName, portNum)
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 static变量。

当我只有一个DeviceCommunicator实例时-效果很好!

但是,我希望DeviceCommunicator类的多个实例可以连接到本地网络上的同一设备或不同设备,考虑到DeviceCommunicator类的输出和输入是static,然后将它们共享(我认为,我已经读过JVM并不能完全保证在DeviceCommunicator的所有实例中,其他运行线程都可以看到静态变量更改-这是一个问题!

我已经进行了一些研究,但没有遇到类似的主题-大多数主题基本上都是“或”的,其中:

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

或者

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

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

我没有意识到这个问题的明显解决方案吗?

提前致谢!

最佳答案

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

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

现在,如果有多个线程正在读取和写入流,则必须先在它们上进行同步。

您还在注释中提到需要发送一个Queue的消息。这也可能是DeviceCommunicator的参数,尽管您将需要创建一个同步列表或其他内容:
List<String> toSendList = Collections.synchronizedList(new ArrayList<String>());
...
new Thread(new DeviceCommunicator(hostName, portNum, in, out, toSendList)).start();

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

09-12 16:16