Шаблон-одиночка и многопоточность в Java

235
14 ноября 2017, 23:04

Существует клиент-серверное приложения, на серверной(мультипотоковой) части я пытаюсь реализовать синглтон:

public class Server {
    private static Server server = new Server();
    public static Server getInstance() {
        return server;
    }
    private ServerSocket myServerSocket = null;
    private boolean ServerOn = true;
    private int clientAmount = 0; //Количество клиентов
    private Server() {
        try {
            myServerSocket = new ServerSocket(2222);
            System.out.println("Подключение сервера прошло успешно.");
            Class.forName("by.markovsky.database.DatabaseConnection");
        }
        catch(ClassNotFoundException exp)
        {
            System.err.print("Не найден класс DatabaseConnection.");
            System.exit(-1);
        }
        catch(IOException ioe) {
            System.err.println("Невозможно создать сервер-сокет на порте " + 2222 + ". Завершение работы...");
            System.exit(-1);
        }
        while(ServerOn) {
            try {
                myServerSocket.setSoTimeout(10);
                Socket clientSocket = myServerSocket.accept();
                System.out.println("Общее количество подключённых клиентов: "+ ++clientAmount);
                ClientServiceThread cliThread = new ClientServiceThread(clientSocket);
                cliThread.start();
            }
            catch(SocketTimeoutException ex){
            }
            catch(IOException ioe) {
                System.out.println("Возникла ошибка подключения. Трассировка стека: ");
                ioe.printStackTrace();
            }
        }
        closeSocket();
    }
    //Отключение сервера
    private void closeSocket(){
        try {
            myServerSocket.close();
            System.out.println("Работа сервера остановлена.");
            System.exit(1);
        }
        catch(Exception ioe) {
            System.err.println("Возникла неожиданная ошибка сервера.");
            System.exit(-1);
        }
    }
    class ClientServiceThread extends Thread {
        private Socket myClientSocket = null;
        private boolean ClientThreadOn = true;
        private ObjectOutputStream out = null;
        private ObjectInputStream in = null;
        private Package pack = null;
        public ClientServiceThread() {
            super();
        }
        ClientServiceThread(Socket s) {
            myClientSocket = s;
        }
        //Новый поток
        public void run() {
            System.out.println("Адрес нового клиента: " + myClientSocket.getInetAddress().getHostName());
            try {
                out = new ObjectOutputStream(myClientSocket.getOutputStream());
                in = new ObjectInputStream(myClientSocket.getInputStream());
                while(ClientThreadOn) {
                    pack = (Package) in.readObject(); //Получение пакета
                    System.out.println("Команда клиента: " + pack.getCommand());
                    //Сервер отключен?
                    if(!ServerOn) { //ВОТ ТУТ КОД ПЕРЕСТАЕТ ВЫПОЛНЯТЬСЯ
                        System.out.print("Сервер отключен.");
                        pack.setAnswer("Сервер отключен.");
                        out.writeObject(pack);
                        out.flush();
                        out.reset();
                        ClientThreadOn = false;
                    }
                }
            }
            catch(Exception e) {
                e.printStackTrace();
            }
            finally {
                try {
                    out.close();
                    in.close();
                    myClientSocket.close();
                    System.out.println("...Клиент отключен");
                }
                catch(IOException ioe) {
                    ioe.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args){
    }
}

Подключение клиента проходит хорошо, однако после отправления сообщения клиент зависает, причём объект отправляется клиентом и получается сервером и при достижении блока if с переменной внешнего класса код перестаёт выполняться(хотя до этого данная переменная уже использовалась внешним классом). Далее, я переделал код для проверки и он заработал.

public class Server {
    private static Server server;
    public static Server getInstance() {
        return server=new Server(); //ДОБАВИЛ ЭТО
    }
    private ServerSocket myServerSocket = null;
    private boolean ServerOn = true;
    private int clientAmount = 0; //Количество клиентов
    private Server() {
        try {
            myServerSocket = new ServerSocket(2222);
            System.out.println("Подключение сервера прошло успешно.");
            Class.forName("by.markovsky.database.DatabaseConnection");
        }
        catch(ClassNotFoundException exp)
        {
            System.err.print("Не найден класс DatabaseConnection.");
            System.exit(-1);
        }
        catch(IOException ioe) {
            System.err.println("Невозможно создать сервер-сокет на порте " + 2222 + ". Завершение работы...");
            System.exit(-1);
        }
        while(ServerOn) {
            try {
                myServerSocket.setSoTimeout(10);
                Socket clientSocket = myServerSocket.accept();
                System.out.println("Общее количество подключённых клиентов: "+ ++clientAmount);
                ClientServiceThread cliThread = new ClientServiceThread(clientSocket);
                cliThread.start();
            }
            catch(SocketTimeoutException ex){
            }
            catch(IOException ioe) {
                System.out.println("Возникла ошибка подключения. Трассировка стека: ");
                ioe.printStackTrace();
            }
        }
        closeSocket();
    }
    //Отключение сервера
    private void closeSocket(){
        try {
            myServerSocket.close();
            System.out.println("Работа сервера остановлена.");
            System.exit(1);
        }
        catch(Exception ioe) {
            System.err.println("Возникла неожиданная ошибка сервера.");
            System.exit(-1);
        }
    }
    class ClientServiceThread extends Thread {
        private Socket myClientSocket = null;
        private boolean ClientThreadOn = true;
        private ObjectOutputStream out = null;
        private ObjectInputStream in = null;
        private Package pack = null;
        public ClientServiceThread() {
            super();
        }
        ClientServiceThread(Socket s) {
            myClientSocket = s;
        }
        //Новый поток
        public void run() {
            System.out.println("Адрес нового клиента: " + myClientSocket.getInetAddress().getHostName());
            try {
                out = new ObjectOutputStream(myClientSocket.getOutputStream());
                in = new ObjectInputStream(myClientSocket.getInputStream());
                while(ClientThreadOn) {
                    pack = (Package) in.readObject(); //Получение пакета
                    System.out.println("Команда клиента: " + pack.getCommand());
                    //Сервер отключен?
                    if(!ServerOn) { //ВОТ ТУТ КОД ПЕРЕСТАЕТ ВЫПОЛНЯТЬСЯ
                        System.out.print("Сервер отключен.");
                        pack.setAnswer("Сервер отключен.");
                        out.writeObject(pack);
                        out.flush();
                        out.reset();
                        ClientThreadOn = false;
                    }
                }
            }
            catch(Exception e) {
                e.printStackTrace();
            }
            finally {
                try {
                    out.close();
                    in.close();
                    myClientSocket.close();
                    System.out.println("...Клиент отключен");
                }
                catch(IOException ioe) {
                    ioe.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args){
          Server.getInstance();
    }
}

Также пробовал заменить private модификатор на protected и код тоже заработал(при этом ide предлагало всё же заменить на private) Вопрос: Почему в первом случае код перестаёт выполняться при достижении private переменной внешнего класса, а во втором всё срабатывает отлично? P.S.: Без синглтона также всё работает отлично

READ ALSO
построение dom из inputstream

построение dom из inputstream

мне надо получить dom документа , который я получаю в виде inputStream есть ли такая возможность ? пробовал

227
Json не возвращает null поле

Json не возвращает null поле

Есть поле String, которое может быть nullИ вот если оно null, то в ответе в json этот null не показывается

228