如何多次实例化一个实现runnable并打开套接字的类?

时间:2012-04-26 15:30:07

标签: java multithreading sockets runnable

我正在开展一个项目,其中我有一个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实例中。

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

提前致谢!

1 个答案:

答案 0 :(得分: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添加方法,您也可以让它也隐藏读取器和写入器流,并且主线程不会直接访问流。 Data hiding是面向对象程序的重要特征之一。