java - 如何通知正在运行的线程发生更改

标签 java multithreading design-patterns

我正在开发一个客户端/服务器项目,该项目监视服务器中的系统事件并向客户端发送通知更改。它由执行监视操作的 Watcher 对象和为连接到它的每个客户端创建线程的服务器对象组成。考虑下面的简化代码(我包含了所有必要的代码)

现在,问题是从 mySrv 对象接收到通知,并且 mySrvpropertyChange 正确执行,并且 disMsg 已填充。但是,我不知道如何访问 ClientHandlerrun 方法来执行 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 。但也存在一些问题:

  1. ClientHandler.runisChanged 变为 true

    时,可能会阻止从客户端连接读取数据
  2. 即使从套接字读取了某些内容,线程也可能会发现 isChanged 为 false。这是因为更改发生在不同的线程中。如果变量被声明为 volatile ,那么这种情况就不会发生。

  3. 服务器接受多个连接,每个连接都有一个不同的线程。但每个线程的 run 方法都可以将 isChanged 设置为 false,因此即使该值传播到所有线程,也只有其中一个线程会打印通知。

    <

我知道这不是完整的答案,但您需要解决这些问题。

关于java - 如何通知正在运行的线程发生更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20846802/

相关文章:

c# - 多线程设计模式

java - Spring Quartz 使用父类构造函数设置基于构造函数的注入(inject)

java - 从 Windows、Mac 和 Linux 上的位置检索文件

java - 如果性别=男性或女性打印结果

multithreading - 无锁数据结构中需要多少个ABA标签位?

design-patterns - 编写出色的软件

java - 如何将POI中的单元格输出转换为java中的文本文件

python - 将队列传递给 ThreadedHTTPServer

java - 如何使用 Java 多线程读取多个文件?

java - 使用 Java 构建插件系统的最佳方法