Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
多线程Java服务器:允许一个线程访问另一个线程_Java_Multithreading_Oop_Coding Style - Fatal编程技术网

多线程Java服务器:允许一个线程访问另一个线程

多线程Java服务器:允许一个线程访问另一个线程,java,multithreading,oop,coding-style,Java,Multithreading,Oop,Coding Style,希望代码本身能在这里解释这个问题: class Server { public void main() { // ... ServerSocket serverSocket = new ServerSocket(PORT); while (true) { Socket socket = serverSocket.accept(); Thread thread = new Thread(new

希望代码本身能在这里解释这个问题:

class Server {

    public void main() {
        // ...
        ServerSocket serverSocket = new ServerSocket(PORT);
        while (true) {
            Socket socket = serverSocket.accept();
            Thread thread = new Thread(new Session(socket));
            thread.start();
        }
        // ..
    }

    public static synchronized Session findByUser(String user) {
        for (int i = 0; i < sessions.size(); i++) {
            Session session = sessions.get(i);
            if (session.getUserID().equals(user)) {
                return session;
            }
        }
        return null;
    }

}

class Session {
    public Session(Socket socket) {
        attach(socket);
    }

    public void attach(Socket socket) {
        // get socket's input and output streams
        // start another thread to handle messaging (if not already started)
    }

    public void run() {
        // ...
        // user logs in and if he's got another session opened, attach to it
        Session session = Server.findByUser(userId);
        if (session != null) {
            // close input and output streams
            // ...
            session.attach(socket);
            return;
        }

        // ..

    }
}
托马斯:

谢谢你的回答

我同意,在现实世界中,在创建
会话
的新实例时使用依赖项注入是一个好主意,但可能还有一个接口,对不对(下面的代码)?尽管我可能应该做一些单元测试,但我不这么认为。然后我只需要一个服务器实例那么,使用静态方法而不是单音方法会是一个巨大的OO犯罪吗?

interface Server {
    Session findByUser(String user);
}

class ServerImpl implements Server {
    public Session findByUser(String user) { }
}

class Session {
   public Session(Server server, Socket socket) { }
} 
关于
attach(…)
方法的一点很好-我甚至从未考虑过对
Session
类进行子类化,这可能就是为什么我没有想到在构造函数中调用public方法会有多危险。但我实际上需要一些公共方法将会话附加到不同的套接字,所以可能需要两个方法

class Session {
    public Session(Socket socket) {
       attach_socket(socket);
    }

    public void attach(Socket socket) {
        attach_socket(socket);
    }

    private void attach_socket(Socket socket) {
        // ...
    }
}
允许会话的客户端调用
attach(…)
似乎是不对的。这可能是只有服务器才能访问的重要方法之一。但是,如果没有C++的友好关系,我该怎么做呢?不知怎的,我想到了内心的阶级,但我并没有考虑太多,所以这可能是一条完全错误的道路

每次我收到一个新连接时,我都会产生一个新线程(并创建一个与之关联的新会话实例)来处理传输。这样,当用户发送登录命令时,服务器就准备好接受新的连接。一旦用户的身份得到验证,我会检查他是否还没有登录(有另一个正在进行的会话)。如果他是,那么我将正在进行的会话与其套接字分离,关闭该套接字,将正在进行的会话连接到当前套接字,然后关闭当前会话。希望这能更清楚地解释实际发生的事情?也许在这里使用单词会话有点不太合适。我真正拥有的是为每个连接(和3个线程)创建4个不同的对象:套接字处理程序、消息发送者、消息接收者和会话(如果这是一个好的解决方案,那是一个不同的问题…)。我只是试着简化源代码来关注这个问题

我完全同意,当您可以使用映射时,迭代会话列表是没有意义的。但我担心这可能是我正在编写的代码所面临的较小问题之一(相信我)。我应该提到的是,它实际上是一些遗留系统,毫不奇怪,最近发现了一些并发性和性能问题。我的任务是修复它。。。当您基本上只掌握了多线程的理论知识,或者仅使用它来显示进度条时,这不是一项容易的任务


如果在这段相当长的澄清之后,您对体系结构有了更多的了解,我将非常愿意倾听。

您应该从创建服务器类OO(即非静态)开始,并在会话类中使用:

class Server {
    public Session findByUser(String user) { }
}

class Session{
   public Session(Server server, Socket socket){}
}
public void attach(..)
必须是私有的,以确保封装和正确初始化。子类可以像这样破坏会话类:

class BadSession extends Session{

@Override public void attach(Socket socket) {
    //this is not initialized at this point

    //now the instance is broken        
  }
}
从客户端调用attach似乎也是无效的

将套接字连接到会话的责任应该是服务器的一部分。这是决定哪个会话获得哪个套接字的正确位置。据我所知,您的代码是使用套接字创建会话。不知何故,您发现用户已经有了一个会话(使用另一个套接字)。现在将当前会话附加到此套接字。现在有两个会话的旧套接字和没有会话的新套接字。我认为传统会话应该有多个套接字,而不是相反:

Session session = findSession(userId);
session.attach(socket);

class Session{
   List<Socket> sockets;
}
Session Session=findSession(userId);
连接(插座);
课堂{
列出插座;
}
在此更改之后,线程将不会分配给会话,而是分配给套接字处理程序,该处理程序处理一个套接字的输入流并相应地更改会话

对方法
公共静态同步会话findByUser(字符串用户)
使用synchronized不足以确保线程安全。您必须确保会话的查找(按用户)和会话的注册(如果用户未知)必须是原子的。语义应该类似于ConcurrentMap。(无论如何,迭代会话列表是无效的。您应该使用。)


我希望这能有所帮助。

static:通过static,您可以确定(在一个类中)可以“实例化”多少个“实例”:一个。这确实限制了类的可用性。(例如,您不能监听另一个套接字。)测试会话实际上是不可能的。(您无法创建服务器模拟。)这是DI(和服务定位器)的动机。附加(…):您可以将其包设为私有包:public void attach(Socket Socket)->void attach(Socket Socket)。但是我仍然认为应该把责任放在服务器上。“将套接字附加到会话的责任应该是服务器的一部分”:您仍然需要会话上的方法(在本例中也是套接字/连接处理程序)来告诉它将自己附加到新的套接字,即使服务器调用它,对吗?你还要怎么编码呢?是的。来自我的代码片段:session.attach(socket)。(附件必须在会话类中)。
Session session = findSession(userId);
session.attach(socket);

class Session{
   List<Socket> sockets;
}