我有以下Thread子类(为了便于阅读,略有简化):
public class ConnectionHandlerThread extends Thread {
private Socket socket;
private volatile boolean disconnected = false;
private ObjectOutputStream out = null;
private ObjectInputStream in = null;
public ConnectionHandlerThread(Socket socket){
this.socket = socket;
}
public void run(){
disconnected = false;
try {
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
while(!disconnected){
try{
Object data = in.readObject();
}
catch(ClassNotFoundException e){
// Handle exception
}
catch(IOException e){
// Handle exception
}
}
}
catch (IOException e) {
// Handle exception
}
}
public void send(Object data){
try{
out.writeObject( data );
}
catch(IOException e){
// Handle exception
}
}
}
当我连接到服务器时,我的客户端(使用Swing GUI)创建了此线程的实例。我觉得奇怪的是我可以从主GUI调用方法send(Object data)
,它可以工作。为什么无限循环和/或对in.readObject()
的调用不能阻止我这样做?我的意思是不应该线程忙于不断做其他事情?这是一个做事的好方法吗?如果没有,为什么不呢?
修改
澄清一下让我感到困惑的是:如果这是在主线程中,它会忙于in.readObject()
直到读取某些东西,然后它才会在循环的下一次迭代中再次开始监听。当然,我知道我可以从另一个线程调用send()
。但是我的思绪在哪里 - “谁”实际上正在执行send()
?我的Thread是在做它,还是调用线程呢?如果是前者,那么如何在while循环和执行send()
方法时忙于等待输入?我只是很难把它包裹起来......
答案 0 :(得分:1)
有两件事:
1)无限循环不会使cpu只与自身保持忙碌。它只是在它可用的时候保持忙碌,但我也使用其他线程。
2)当你打电话给
时发送(对象数据)
你没有从你的线程中做到这一点,因此请记住1)没有什么奇怪的,它被称为
示例:
代码:
public class Main {
public static void main(String[] args) {
InfiniteThread t = new InfiniteThread();
t.start();
for(int i=0;i<10;i++) {
t.fromOut(i);
}
}
@DebugLog
public static class InfiniteThread extends Thread {
public void run() {
for(int i=0;i<10;i++) {
fromIn();
}
}
private void fromIn() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void fromOut(Object data){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出:
InfiniteThread ::⇢()[线程:“main”] InfiniteThread ::⇠ [0ms] InfiniteThread ::⇢run()[线程:“Thread-0”] InfiniteThread ::⇢fromIn()[Thread:“Thread-0”] InfiniteThread ::⇢ fromOut(data = 0)[线程:“main”] InfiniteThread ::⇠fromOut[500ms] InfiniteThread ::⇢fromOut(data = 1)[Thread:“main”] InfiniteThread :: ⇠fromIn[1000ms] InfiniteThread ::⇢fromIn()[Thread:“Thread-0”] InfiniteThread ::⇠fromOut [500ms] InfiniteThread ::⇢ fromOut(data = 2)[线程:“主要”] InfiniteThread ::⇠fromOut[500ms] InfiniteThread ::⇢fromOut(data = 3)[Thread:“main”] InfiniteThread :: ⇠fromIn[1000ms] InfiniteThread ::⇢fromIn()[Thread:“Thread-0”] InfiniteThread ::⇠fromOut [500ms] InfiniteThread ::⇢ fromOut(data = 4)[线程:“主要”] InfiniteThread ::⇠fromOut[500ms] InfiniteThread ::⇢fromOut(data = 5)[Thread:“main”] InfiniteThread :: ⇠fromIn[1000ms] InfiniteThread ::⇢fromIn()[Thread:“Thread-0”] InfiniteThread ::⇠fromOut [500ms] InfiniteThread ::⇢ fromOut(data = 6)[线程:“main”] InfiniteThread ::⇠fromOut[500ms] InfiniteThread ::⇢fromOut(data = 7)[Thread:“main”] InfiniteThread :: ⇠fromIn[1000ms] InfiniteThread ::⇢fromIn()[Thread:“Thread-0”] InfiniteThread ::⇠fromOut [500ms] InfiniteThread ::⇢ fromOut(data = 8)[线程:“main”] InfiniteThread ::⇠fromOut[500ms] InfiniteThread ::⇢fromOut(data = 9)[Thread:“main”] InfiniteThread :: ⇠fromIn[1000ms] InfiniteThread ::⇢fromIn()[Thread:“Thread-0”] InfiniteThread ::⇠fromOut [500ms] InfiniteThread ::⇠fromIn [1000ms] InfiniteThread ::⇢fromIn()[线程:“Thread-0”] InfiniteThread ::⇠fromIn [1000ms] InfiniteThread ::⇢fromIn() [Thread:“Thread-0”] InfiniteThread ::⇠fromIn [1000ms] InfiniteThread ::⇢fromIn()[Thread:“Thread-0”] InfiniteThread ::⇠fromIn [1000ms] InfiniteThread ::⇢fromIn()[Thread:“Thread-0”] InfiniteThread ::⇠ fromIn [1000ms] InfiniteThread ::⇠run [10003ms]
答案 1 :(得分:1)
@jameslarge是的,我现在很困惑......
Thread
对象不是线程:它可以用于配置,创建和与线程交互的方法。您正在使用ConnectionHandlerThread
来完成所有这些,并且您也在使用它(通过覆盖run()
方法)来定义线程所做的工作,并且您也在使用它(由几个private fields)表示线程操作的连接状态。这有很多超载。
一位作者说过,#34;编写一个对象太少的程序很容易。编写一个包含太多对象的文件很难。&#34;
我会重新编写代码,使用三个不同的对象来完成ConnectionHandlerThread现在执行的三个不同的工作:
public class Connection {
private Socket socket;
private volatile boolean connected = true;
private ObjectOutputStream out = null;
private ObjectInputStream in = null;
public Connection(Socket socket){
this.socket = socket;
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
}
public void send(Object data){
try{
out.writeObject( data );
}
catch(IOException e){
handleExceptionInSend(e);
}
}
public Object receive() {
try{
Object data = in.readObject();
}
catch(ClassNotFoundException e){
handleExceptionInReceive(e);
return NULL;
}
catch(IOException e){
handleExceptionInReceive(e);
return NULL;
}
return Object;
}
public boolean isConnected() {
return connected;
}
...
}
public class ConnectionListener implements Runnable {
private final connection;
public ConnectionRunner(Connection connection) {
this->connection = connection;
}
public void run(){
while(connection.isConnected()){
Object o = connection.receive();
if (o) {
doSomethingWith(o);
}
}
}
}
public class Whatever {
...
public void whateverelse( ) {
Socket socket = ...;
Connection connection = new Connection(socket);
ConnectionListener listener = new ConnectionListener(connection);
Thread connectionThread = new Thread(listener);
connectionThread.start();
...
}
...
}
connection
对象知道如何发送和接收数据。
listener
对象定义了线程的作用:即,它从连接接收对象直到! isConnected()
并且它对它们做了一些事情。
最后,connectionThread
对象是启动线程的原因(可以用来等待它完成等)。
它比您编写的代码更多,但是IMO,它更容易理解,因为它更容易看到每个单独作品的责任。有时,特别是如果您与其他开发人员合作,使代码易于理解比将其缩小更重要。
答案 2 :(得分:-1)
这是有效的,因为在SWING / GUI中你正在做类似的事情:
ConnectionHandlerThread myThread = ConnectionHandlerThread(new Socket());
现在send()
方法是公共的,因此您可以在执行
myThread.send(data);
诀窍是你在Thread中使用套接字,这都是因为你在类ConnectionHandlerThread
的构造函数中传递了一个套接字