Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/365.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单例网络实现runnable_Java_Networking_Runnable - Fatal编程技术网

java单例网络实现runnable

java单例网络实现runnable,java,networking,runnable,Java,Networking,Runnable,我正在编写一个网络单例类,它需要在一个线程中运行,到目前为止没有问题,但是我无法让它工作 网络类: public class Network extends Thread { private static Network cachedInstance = new Network(); private PrintWriter out; private BufferedReader in; private Network() { }

我正在编写一个网络单例类,它需要在一个线程中运行,到目前为止没有问题,但是我无法让它工作

网络类:

public class Network extends Thread {    
    private static Network cachedInstance = new Network();

    private PrintWriter out;
    private BufferedReader in;

    private Network() {        
    }

    private void init() {
        try {
            Socket clientSocket = new Socket(Config.HOST_NAME, Config.HOST_PORT);
            out = new PrintWriter(clientSocket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

            String fromServer;
            while ((fromServer = in.readLine()) != null) {
                System.out.println("Server: " + fromServer);
            }

        } catch (IOException ex) {
            Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static Network getInstance() {
        return cachedInstance;
    }

    public void send(final String string) {
        out.println(string);
    }

    @Override
    public void run() {
        init();
    }
}
控制器类的一部分:

public void clientTest() {
    int random = new Random().nextInt(1000);
    Network.getInstance().start();
    Network.getInstance().send(random + "");
}
我得到的错误是:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at network.Network.send(Network.java:52)
at controller.Controller.clientTest(Controller.java:126)
因此,看起来单个网络实例没有正确实例化,这在理论上是不可能的

我的第二个问题是,我是否可以避免使用此选项:

Network.getInstance().start();
换句话说,我希望确保只创建一个线程(网络类),并且在初始化类时,它在默认情况下始终运行。以目前的方式,情况还不错,但我只是觉得会更好

对于想知道我为什么使用这种方法的人:基本上我只想使用Network.send()发送到固定服务器。该服务器当然也可以将内容发送回,但在这种情况下,网络需要在某个时候做出反应并从控制器调用方法

问候

编辑:根据反应提出的解决方案

Network.class:

public class Network implements Runnable {    
    private static final Network cachedInstance;
    static {
        Network tempInstance = null;
        try {
            tempInstance = new Network(Config.HOST_NAME, Config.HOST_PORT);
        } catch (IOException ex) {
            Logger.getLogger(Network.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            cachedInstance = tempInstance;
        }
    }

    private final Socket clientSocket;
    private final PrintWriter out;
    private final BufferedReader in;

    private Network(final String hostname, final int port) throws IOException {
        clientSocket = new Socket(hostname, port);
        out = new PrintWriter(clientSocket.getOutputStream(), true);        
        in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    }

    public static Network getInstance() {
        return cachedInstance;
    }

    @Override
    public void run() {
        try {
            String fromServer;
            while ((fromServer = in.readLine()) != null) {
                System.out.println("Server: " + fromServer);
            }
        } catch (IOException ex) {
            Logger.getLogger(Network.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void send(final String string) {
        out.println(string);
    }

    public void close() {
        try {
            in.close();
            out.close();
            clientSocket.close();
        } catch (IOException ex) {
            Logger.getLogger(Network.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
呼叫代码:

public void clientTest() {
    int random = new Random().nextInt(1000);
    Network network = Network.getInstance();
    new Thread(network).start();
    network.send(random + "");
    network.close();
}

这只是为了测试,实际上连接需要保持打开状态,直到用户关闭程序。

在线程上调用
start()
时,线程实际运行之前需要一段时间。在调用
run()
之前,您正在调用
send()
,因此在初始化
out
之前。不要这样做。等待来自运行线程的消息,然后才可以安全地调用
send()
。您可以在一个简单的
对象上使用
wait()
notify()
来执行此操作


为了避免客户端调用
start()
——当然,可以从
网络
的构造函数调用
start()

在线程上调用
start()
时,线程实际运行之前会经过一段时间。在调用
run()
之前,您正在调用
send()
,因此在初始化
out
之前。不要这样做。等待来自运行线程的消息,然后才可以安全地调用
send()
。您可以在一个简单的
对象上使用
wait()
notify()
来执行此操作


为了避免客户端调用
start()
——当然,可以从
Network
的构造函数调用
start()

这个问题的一个简单解决方案是在启动线程之前建立连接,这样就不用担心这个争用条件

public class Network implements Runnable, Closeable {    
    private final Socket clientSocket;
    private final PrintWriter out;
    private final BufferedReader in;
    private volatile boolean closed = false;

    public Network(String hostname, int port) throws IOException {        
        clientSocket = new Socket(hostname, port);
        out = new PrintWriter(clientSocket.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    }

    public void run() {
        try {
            for(String fromServer; (fromServer = in.readLine()) != null;) 
                System.out.println("Server: " + fromServer);
        } catch (IOException ex) {
            if (!closed)
                Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void send(String line) {
        out.println(line);
    }

    public void close() {
        closed = true;
        try { clientSocket.close(); } catch (IOException ignored) { }
    }
}
用于测试

@Test
public void testClient() {
    Network network = new Network(Config.HOSTNAME, Config.PORT)
    new Thread(network).start();

    int random = new Random().nextInt(1000);
    network.send(random + "");
    network.close();
}

注意:使用有状态的单例类会使单元测试非常困难,因为您必须将单例重置回其初始状态,否则一个测试可能会影响另一个测试,并且您运行的顺序可能会有所不同。在上述测试中,它是独立的,没有其他测试受到损害。;)

这个问题的一个简单解决方案是在启动线程之前建立连接,这样就不必担心这种争用情况

public class Network implements Runnable, Closeable {    
    private final Socket clientSocket;
    private final PrintWriter out;
    private final BufferedReader in;
    private volatile boolean closed = false;

    public Network(String hostname, int port) throws IOException {        
        clientSocket = new Socket(hostname, port);
        out = new PrintWriter(clientSocket.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    }

    public void run() {
        try {
            for(String fromServer; (fromServer = in.readLine()) != null;) 
                System.out.println("Server: " + fromServer);
        } catch (IOException ex) {
            if (!closed)
                Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void send(String line) {
        out.println(line);
    }

    public void close() {
        closed = true;
        try { clientSocket.close(); } catch (IOException ignored) { }
    }
}
用于测试

@Test
public void testClient() {
    Network network = new Network(Config.HOSTNAME, Config.PORT)
    new Thread(network).start();

    int random = new Random().nextInt(1000);
    network.send(random + "");
    network.close();
}

注意:使用有状态的单例类会使单元测试非常困难,因为您必须将单例重置回其初始状态,否则一个测试可能会影响另一个测试,并且您运行的顺序可能会有所不同。在上述测试中,它是独立的,没有其他测试受到损害。;)

“等待来自运行线程的消息”你能给我解释更多关于这个的信息吗?我该如何等待该消息?“等待来自运行线程的消息”您可以向我详细解释一下吗?我如何等待该消息?在设置
out
之前,您正在调用send。顺便说一句,您需要将字段
out
设置为
volatile
字段,否则您可能永远不会看到它被设置。您在设置
out
之前调用send。顺便说一句,您需要将字段
设置为一个
易变的
字段,否则您可能永远不会看到它被设置。非常感谢!事实上,我已经对这个问题放弃了希望。我现在就测试它,但它肯定会工作。不过有一个问题:构造函数为什么抛出IOException?这是否意味着此代码的调用方需要进行异常处理?在我看来,这很烦人,因为类本身(这里的网络)也可以自己做?它可以做异常处理,但通常只有调用方知道应该做什么。在任何情况下,您都不想创建一个实际上没有连接到任何东西的网络。i、 e.死物。如果套接字无法连接,您希望它做什么?我提出了一个建议的解决方案,其中包括它是单例的,您能检查一下吗?:)我很抱歉,如果我没有100%遵循你的指导原则。这是更好的,它解决了比赛条件。注意:如果您在网络连接失败后尝试使用网络,您将收到NullPointerException。非常感谢!事实上,我已经对这个问题放弃了希望。我现在就测试它,但它肯定会工作。不过有一个问题:构造函数为什么抛出IOException?这是否意味着此代码的调用方需要进行异常处理?在我看来,这很烦人,因为类本身(这里的网络)也可以自己做?它可以做异常处理,但通常只有调用方知道应该做什么。在任何情况下,您都不想创建一个实际上没有连接到任何东西的网络。i、 e.死物。如果套接字无法连接,您希望它做什么?我提出了一个建议的解决方案,其中包括它是单例的,您能检查一下吗?:)我很抱歉,如果我没有100%遵循你的指导原则。这是更好的,它解决了比赛条件。注意:如果在网络连接失败后尝试使用该网络,您将获得NullPointerException。