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

1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд
Загрузка...

Вопрос:


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

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.: Без синглтона также всё работает отлично

Автор вопроса: clms7n

Попробуйте ServerOn объявить volatile, т.к. эта переменная используется в разных потоках. Это исключит её кеширование процессором.

А так же, используйте инструмент отладки C:Program FilesJavajdkbinjvisualvm.exe там есть возможность получить Dump Threads и посмотреть на чём виснет.

Источник

Вам также может быть интересно:

Drag and Drop UWP — c# xaml mvvm
Вопрос: Нужно иметь возможность добавлять изображения в приложение путем перетаскивания из файловой системы У Grid включил AllowDrop. Но как добавить перетаскиваемые изображения в коллекцию? Т.к. те ...
Растягивание Высоты , Резина — html css html5
Вопрос: Здравствуйте! Реализовал резиновый дизайн. Растягивается ширина, но длина по % не растягивается. Возможно ли это реализовать? Или так и задумано, растягивание только на ширину ...
Jquery position().left Как быть на мобильниках? — javascript jquery css
Вопрос: На мобильных устройствах, если зумишь экран, position всегда разный. $('g').position().left Как сделать так, чтобы он не менял свои значения? Автор вопроса: ...
Jquery position().left Как быть на мобильниках? — javascript jquery css
Вопрос: На мобильных устройствах, если зумишь экран, position всегда разный. $('g').position().left Как сделать так, чтобы он не менял свои значения? Автор вопроса: ...
requestAnimation и очередность отрисовки — javascript canvas
Вопрос: Здравствуйте! Реализовал 2D игру и в Edge работает все плавно и круто, но в Firefox'e подвисает, сказали, что нужно сделать, чтобы раз-два момент и все ...
Контекстное/всплывающее меню в Android — java android popup
Вопрос: Есть ли техническая возможность сделать приложение, добавляющее свое контекстное или всплывающее меню в любом месте системы? Хочу, чтобы при выделении любого текста появлялась дополнительная кнопка ...
Контекстное/всплывающее меню в Android — java android popup
Вопрос: Есть ли техническая возможность сделать приложение, добавляющее свое контекстное или всплывающее меню в любом месте системы? Хочу, чтобы при выделении любого текста появлялась дополнительная кнопка ...
Завершить службы циклом — c# windows-service
Вопрос: Можно ли остановить службы циклом? У меня есть список служб, занёс их в List List<string> name = new List<string> { "AdobeARMservice", "RemoteRegistry", "TermService", "Messenger", "SSDPSRV", ...
Завершить службы циклом — c# windows-service
Вопрос: Можно ли остановить службы циклом? У меня есть список служб, занёс их в List List<string> name = new List<string> { "AdobeARMservice", "RemoteRegistry", "TermService", "Messenger", "SSDPSRV", ...
RecyclerView — разная разметка — android recyclerview
Вопрос: Смотрел, я смотрел в сторону RecyclerView и наконец решил кинуть ListView и на тебе! В "плохом прошлом" мой ListView использовался для двух разметок. Сейчас я ...
RecyclerView — разная разметка — android recyclerview
Вопрос: Смотрел, я смотрел в сторону RecyclerView и наконец решил кинуть ListView и на тебе! В "плохом прошлом" мой ListView использовался для двух разметок. Сейчас я ...
Как правильно передать массив аргументом для пользовательской функции — php
Вопрос: Если не брать в функцию все это, тогда результат работает. А если вот так в функции все выполнять, тогда PHP ругается: «Invalid ...
Как правильно передать массив аргументом для пользовательской функции — php
Вопрос: Если не брать в функцию все это, тогда результат работает. А если вот так в функции все выполнять, тогда PHP ругается: «Invalid ...
ViewPager внутри ViewPager — такие матрешки работают? — android viewpager
Вопрос: Доброго времени суток. Назрела новая задача. Есть каталог мастеров. При выборе конкретного мастера открывается его страница (активити с ViewPager), и теперь мастеров можно перелистывать свайпом. ...
Почему id всегда 1 Yii2 — yii авторизация
Вопрос: Использую все как по документации. Для получения информации о пользователе использую $identity = $model->findOne(]); И каким бы не был email, id пользователя всегда ...