Singleton Pattern and Multithreading in Java Baeldung

Question:

There is a client-server application, on the server-side (multi-threaded) part I am trying to implement a singleton:

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){

    }

}

The client connection goes well, but after sending the message, the client hangs up, and the object is sent by the client and received by the server, and when the if block is reached with a variable of the external class, the code stops executing (although before that this variable was already used by the external class). Next, I redid the test code and it worked.

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();
    }

}

I also tried to replace the private modifier with protected and the code also worked (while ide suggested replacing it with private) Question: Why in the first case does the code stop executing when the private variable of the external class is reached, and in the second everything works fine? PS: Without the singleton, everything also works fine

Answer:

Try to declare ServerOn volatile, because this variable is used in different threads. This will prevent it from being cached by the processor.

And also, use the debugging tool C: \ Program Files \ Java \ jdk \ bin \ jvisualvm.exe there you can get Dump Threads and see what hangs on.

Scroll to Top
AllEscort