我正在开展一个项目,其中我有一个DeviceCommunicator
课,implements Runnable
。目前,主类实例化DeviceCommunicator
的单个实例,该实例最终使用Socket
库连接到本地网络上的设备。
最后,我的意思是,如果需要发送消息,则DeviceCommunicator
的实例打开与设备的套接字连接,发送消息,然后启动新线程以接收来自套接字的数据通过以下代码行:
new Thread(new DeviceCommunicator()).start();
编辑:澄清一下,这是程序执行时的操作顺序:
1)MAIN
类实例化DeviceCommunicator
类w /构造函数,如:
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
变量。< / p>
当我只有DeviceCommunicator
的一个实例时 - 这很有效!
但是,我希望DeviceCommunicator
类的多个实例可以连接到本地网络上的相同或不同的设备,但考虑到输出和输入的事实在DeviceCommunicator
类中static
,然后它们被共享(我想,我已经读过,JVM并不能完全保证静态变量更改对其他正在运行的线程可见) DeviceCommunicator
的实例 - 这是一个问题!
我做了一些研究,但我没有遇到过类似的话题 - 大多数主题基本上都是“或者 - 或者”:
A)主题是关于线程套接字通信,其中“非阻塞”通信是通过使用静态变量来完成的。
或
B)考虑一个简单的implements Runnable
案例,其中一个线程将完成一个(通常是简单的)任务,而另一个线程完成另一个(通常是略微修改的)任务。
BufferedReader
传递给侦听DeviceCommunicator
线程,但是我正在实现要发送的消息队列(以防万一)有网络问题);因此,如果需要发送消息,它只是获取队列中的第一个元素并将其打印到套接字连接,我想在监听线程中验证消息是否被设备正确接收。如果消息被正确接收,那么我想从队列中删除元素,但这再次造成问题 - 在Java中传递变量总是按值而不是通过引用!因此,如果我要传递队列中的输入BufferedReader
和,则在侦听DeviceCommunicator
中正在修改的队列将不是需要修改的实际队列在主DeviceCommunicator
实例中。
我不知道这个问题的明显解决方案吗?
提前致谢!
答案 0 :(得分:2)
如果您可以控制DeviceCommunicator
类,我会将您需要的Stream
或Reader
对象作为参数传递给构造函数。我肯定会不以这种方式使用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是面向对象程序的重要特征之一。