我正在开发一个客户端/服务器项目,该项目监视服务器中的系统事件并向客户端发送通知更改。它由执行监视操作的 Watcher 对象和为连接到它的每个客户端创建线程的服务器对象组成。考虑下面的简化代码(我包含了所有必要的代码)
现在,问题是从 mySrv
对象接收到通知,并且 mySrv
的 propertyChange
正确执行,并且 disMsg
已填充。但是,我不知道如何访问 ClientHandler
的 run
方法来执行 notifyStatusChange()
将更改发送给客户端。我尝试加入线程和许多不同的东西,但没有成功。如果有人知道更好的方法或指出我的错误和最佳实践,或者具体向我展示如何实现这一目标,我将非常感激。
谢谢
class MyServer implements PropertyChangeListener {
// all the fields and imports are removed for the sake of brevity
public class ClientHandler implements Runnable {
BufferedReader reader;
Socket socket;
InputStreamReader iReader;
public ClientHandler(Socket ClientSocket) {
try {
socket = ClientSocket;
iReader = new InputStreamReader(socket.getInputStream());
reader = new BufferedReader(iReader);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void run() {
String clientMessage;
try {
while (true) {
if (((clientMessage = reader.readLine()) != null)) {
System.out.println("Client: " + clientMessage);
}
if (isChanged) {
System.out.println("Server1: " + dispMsg);
notifyStatusChange();
isChanged = false;
}
}
} catch (IOException ex) {
Logger.getLogger(MyServer.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(MyServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void goServer() {
try {
ss = new ServerSocket(1234);
while (true) {
s = ss.accept();
PrintWriter writer = new PrintWriter(s.getOutputStream(), true);
Thread t = new Thread(new ClientHandler((s)), "Thread for Client #" + counter);
t.start();
System.out.println("Connection " + counter + " received from: "
+ s.getInetAddress().getHostName());
counter++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException ex) {
Logger.getLogger(MyServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public MyServer() {
isChanged = false;
if (dispMsg == null) {
dispMsg = "Waiting for a change...";
}
}
@Override
public void propertyChange(PropertyChangeEvent pce) {
isChanged = true;
dispMsg = "Event to String: " + pce.toString() + "\n"
+ "Property Name: " + pce.getPropertyName() + "\n"
+ "Old Value" + pce.getOldValue() + "\n";
}
public void notifyStatusChange() throws IOException {
PrintWriter pw = new PrintWriter(s.getOutputStream());
pw.println(dispMsg);
}
public static void main(String[] args) {
try {
Watcher myWatcher = new WatcherDir();
MyServer mySrv = new MyServer();
myWatcher.addPropertyChangeListener(mySrv);
myWatcher.start();
mySrv.goServer();
myWatcher.join();
} catch (IOException ex) {
Logger.getLogger(MyServer.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(MyServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
最佳答案
我可以在这里看到一些不同的问题。
服务器似乎等待来自客户端的连接,并在收到连接时创建并启动 ClientHandler
线程。一旦收到这样的连接,其 run
方法将在其自己的线程中执行。
所以此时我们有两个线程,服务器线程和客户端线程,但是如果客户端在连接后没有向套接字写入任何内容,则线程将阻塞在 clientMessage = reader.readLine() )
现在让我们假设在主线程中调用了propertyChange
,并将isChanged
设置为true
。如果我理解正确,您期望调用 notifyStatusChange
。但也存在一些问题:
时,可能会阻止从客户端连接读取数据ClientHandler.run
当isChanged
变为true
即使从套接字读取了某些内容,线程也可能会发现
isChanged
为 false。这是因为更改发生在不同的线程中。如果变量被声明为volatile
,那么这种情况就不会发生。服务器接受多个连接,每个连接都有一个不同的线程。但每个线程的 run 方法都可以将
<isChanged
设置为false
,因此即使该值传播到所有线程,也只有其中一个线程会打印通知。
我知道这不是完整的答案,但您需要解决这些问题。
关于java - 如何通知正在运行的线程发生更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20846802/