1

我正在做一个项目,其中我有一堂课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并打开Socket与 hostName/portNum 的连接,例如:

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实例中修改的实际队列。

这个问题有我不知道的明显解决方案吗?

提前致谢!

4

1 回答 1

2

如果您可以控制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,您也许可以让它也隐藏读取器和写入器流,并且主线程不会直接访问流。 数据隐藏是面向对象程序的重要特征之一。

于 2012-04-26T17:08:10.147 回答