将打开的资源传递给线程是好习惯吗?
Is it good practice to pass opened resources to threads?
我有一个 class MesssageReader
,它在单独的线程中从流中读取消息。现在,当我第一次创建解决方案时,我在线程 class 之外创建了流对象,然后将其作为对 MessageReader
class 的引用传递。我通过我的自定义界面传递它,因为在某些时候我想改变流 reader class。如果 reader 线程收到指示消息流结束的特殊消息,它会正常结束。创建流的主线程关闭它。现在,我担心的是这是一个糟糕的设计?因为,如果我在 reader 线程之外创建一个流,其他人可能会关闭它,这可能会导致问题。但是,另一方面,我也在 reader 线程之外创建了套接字,这有意义吗?因为,您可以创建更多线程来读取来自同一连接的消息。是在 reader 线程之外还是在内部创建所需的流,并让线程处理流的打开和关闭更好(但仍然可以灵活地创建不同的流 options/objects)?
这是我的例子 class:
public class MessageReader implements Runnable {
private MessageInputReader reader;
/* Custom interface for reading messages */
public MessageReader(MessageInputReader reader) {
this.reader = reader;
}
public void run() {
String line = null;
try {
while ((line = reader.readMessage()) != null) {
if ("BYE".equals(line)) {
break;
}
System.out.println(line);
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
public class ReaderExample {
public static void main(String[] args) {
Socket clientSocket = null;
MessageBufferStream bufferedStream = null;
MessageReader reader;
try {
clientSocket = new Socket("hostname", 4060);
bufferedStream = new MessageBufferStream(clientSocket);
reader = new MessageReader(bufferedStream);
(new Thread(reader)).start();
someBlockingMethodWhichDoesOtherWork();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bufferedStream != null)
bufferedStream.closeStream();
if (clientSocket != null)
clientSocket.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
}
这里是第二个选项:
public class MessageReader implements Runnable {
private MessageBufferStream reader;
public MessageReader(Socket clientSocket) throws IOException {
/* I could probably create a factory method here which would
* return different stream objects and achieve the same flexibility as in the first example? */
this.reader = new MessageBufferStream(clientSocket);
}
public void run() {
String line = null;
try {
while ((line = reader.readMessage()) != null) {
if ("BYE".equals(line)) {
break;
}
System.out.println(line);
}
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
if (reader != null)
reader.closeStream();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
下面是代码的其余部分:
public interface MessageInputStream {
public String readMessage() throws IOException;
public void closeStream() throws IOException;
}
public class MessageBufferStream implements MessageInputStream {
private BufferedReader reader;
public MessageBufferStream(Socket clientSocket) throws IOException {
this.reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
@Override
public String readMessage() throws IOException {
return reader.readLine();
}
@Override
public void closeStream() throws IOException {
reader.close();
}
}
Now, when I first created the solution I've created the stream object outside of the thread class, and then passed it as a reference to the MessageReader class. ... my concern here is that this is a bad design?
可能吧。您当然需要在线程外部创建 Socket
,但我认为在该套接字上启动流可能最好在线程内部完成。主线程可能保留对 Socket
的引用(见下文),但分叉线程处理套接字上流的打开,并且还将负责在消息完成时关闭流。
Since, if I create a stream outside of the reader thread someone else might close it and it could cause problems.
您当然可以编写主线程代码,以便在出现问题时忘记流对象。主线程可能希望保留 Socket
的知识,有时这是个好主意。如果你想停止套接字上的处理,因为超时已经过期或应用程序正在关闭,主线程可以关闭套接字,这会导致 IO 方法抛出 IOException
让你的线程有机会干净地关闭.这是一个很好用的模式。
这不是好事或坏事。这与其说是实践问题,不如说是生命周期管理。如果您注意控制传递给线程的资源的管理,并确保它在使用前处于打开状态,并且在仍然需要时从不关闭,那么您就可以了。
文档 是这里的最佳实践。明确预期的内容和必须发生的内容,这样当您或其他人稍后查看时,您就不会遇到麻烦。在打开和关闭资源的位置进行解释。在您的线程代码或任何地方,记录 pre 和 post 条件以及对资源生命周期所做的任何假设。等等
现在这当然假设了关于所述资源的一些事情。特别是,它要么是线程安全的,要么你注意不要通过其他方式(实际同步或简单的设计不变量)同时从多个线程访问它,并且所述资源可以用于不同的thread 而不是构建它的线程(为此你必须查阅它的文档或源代码。例如,如果资源在构造时分配和初始化线程本地存储,你可能别无选择,只能在线程本身上打开它。
我有一个 class MesssageReader
,它在单独的线程中从流中读取消息。现在,当我第一次创建解决方案时,我在线程 class 之外创建了流对象,然后将其作为对 MessageReader
class 的引用传递。我通过我的自定义界面传递它,因为在某些时候我想改变流 reader class。如果 reader 线程收到指示消息流结束的特殊消息,它会正常结束。创建流的主线程关闭它。现在,我担心的是这是一个糟糕的设计?因为,如果我在 reader 线程之外创建一个流,其他人可能会关闭它,这可能会导致问题。但是,另一方面,我也在 reader 线程之外创建了套接字,这有意义吗?因为,您可以创建更多线程来读取来自同一连接的消息。是在 reader 线程之外还是在内部创建所需的流,并让线程处理流的打开和关闭更好(但仍然可以灵活地创建不同的流 options/objects)?
这是我的例子 class:
public class MessageReader implements Runnable {
private MessageInputReader reader;
/* Custom interface for reading messages */
public MessageReader(MessageInputReader reader) {
this.reader = reader;
}
public void run() {
String line = null;
try {
while ((line = reader.readMessage()) != null) {
if ("BYE".equals(line)) {
break;
}
System.out.println(line);
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
public class ReaderExample {
public static void main(String[] args) {
Socket clientSocket = null;
MessageBufferStream bufferedStream = null;
MessageReader reader;
try {
clientSocket = new Socket("hostname", 4060);
bufferedStream = new MessageBufferStream(clientSocket);
reader = new MessageReader(bufferedStream);
(new Thread(reader)).start();
someBlockingMethodWhichDoesOtherWork();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bufferedStream != null)
bufferedStream.closeStream();
if (clientSocket != null)
clientSocket.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
}
这里是第二个选项:
public class MessageReader implements Runnable {
private MessageBufferStream reader;
public MessageReader(Socket clientSocket) throws IOException {
/* I could probably create a factory method here which would
* return different stream objects and achieve the same flexibility as in the first example? */
this.reader = new MessageBufferStream(clientSocket);
}
public void run() {
String line = null;
try {
while ((line = reader.readMessage()) != null) {
if ("BYE".equals(line)) {
break;
}
System.out.println(line);
}
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
if (reader != null)
reader.closeStream();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
下面是代码的其余部分:
public interface MessageInputStream {
public String readMessage() throws IOException;
public void closeStream() throws IOException;
}
public class MessageBufferStream implements MessageInputStream {
private BufferedReader reader;
public MessageBufferStream(Socket clientSocket) throws IOException {
this.reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
@Override
public String readMessage() throws IOException {
return reader.readLine();
}
@Override
public void closeStream() throws IOException {
reader.close();
}
}
Now, when I first created the solution I've created the stream object outside of the thread class, and then passed it as a reference to the MessageReader class. ... my concern here is that this is a bad design?
可能吧。您当然需要在线程外部创建 Socket
,但我认为在该套接字上启动流可能最好在线程内部完成。主线程可能保留对 Socket
的引用(见下文),但分叉线程处理套接字上流的打开,并且还将负责在消息完成时关闭流。
Since, if I create a stream outside of the reader thread someone else might close it and it could cause problems.
您当然可以编写主线程代码,以便在出现问题时忘记流对象。主线程可能希望保留 Socket
的知识,有时这是个好主意。如果你想停止套接字上的处理,因为超时已经过期或应用程序正在关闭,主线程可以关闭套接字,这会导致 IO 方法抛出 IOException
让你的线程有机会干净地关闭.这是一个很好用的模式。
这不是好事或坏事。这与其说是实践问题,不如说是生命周期管理。如果您注意控制传递给线程的资源的管理,并确保它在使用前处于打开状态,并且在仍然需要时从不关闭,那么您就可以了。
文档 是这里的最佳实践。明确预期的内容和必须发生的内容,这样当您或其他人稍后查看时,您就不会遇到麻烦。在打开和关闭资源的位置进行解释。在您的线程代码或任何地方,记录 pre 和 post 条件以及对资源生命周期所做的任何假设。等等
现在这当然假设了关于所述资源的一些事情。特别是,它要么是线程安全的,要么你注意不要通过其他方式(实际同步或简单的设计不变量)同时从多个线程访问它,并且所述资源可以用于不同的thread 而不是构建它的线程(为此你必须查阅它的文档或源代码。例如,如果资源在构造时分配和初始化线程本地存储,你可能别无选择,只能在线程本身上打开它。