Шаблон-одиночка и многопоточность в 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 и посмотреть на чём виснет.

Источник

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

Delphi REST library обновить Access Token google api — delphi api rest
Вопрос: У меня вопрос по работе с сетью в Delphi С помощью REST library (с которой знаком поверхностно) подключаюсь к Google drive api в OAuth2Authenticator-е успешно получил ...
Как быстро удалить и очистить 500к+ файлов в linux? — linux
Вопрос: Есть интересная задача: Есть папка в котором скопилось 500000 файлов логов. Нужно удалить файлы, которые не используются программой. Нужно очистить файлы, которые используется программой. Я попробовал так: for i ...
Android отключить полноэкранный режим — android полноэкранный
Вопрос: Добрый день! Столкнулись с такой проблемой, приложение работает в полноэкранном режиме, при этом требуется постоянный вертикальный режим. С мобильными приложениями все хорошо, да и с планшетами ...
Проблема с синхронизацией времени на сервере Ubuntu 16.04 — ubuntu ntp
Вопрос: Есть 2 сервера находящихся в 1 часовом поясе. Наблюдается проблема с расхождением времени около 70 секунд. В чем может быть проблема, с чего начать, ...
Избежать большого количество подзапросов SQL — sql sql-server
Вопрос: В WinForms приложении существует dataGridView, который заполняется около 1000 строк и 107 столбцов при входе в приложение из БД MS SQL. Хранимая процедура, большинство данных ...
Добавление элемента в модель — c++ qt
Вопрос: Не могу понять как происходит взаимодействие модели и представления. Нужно добавить элемент в модель и установить для него виджет в отображении. У QListView есть метод ...
Выполнить команду на удалённом Windows-сервере из-под Linux — python linux windows
Вопрос: Есть зоопарк серверов числом более 150. На всех стоят Windows Server 2008, 2012, 2012 R2. Машины не в домене, физически находятся по всей стране ...
Протестировать процедуру в макросе Microsoft Project — vba project-management
Вопрос: Я работаю с Microsoft Project 2013. На мою просьбу написать макрос, «товарищ» ответил мне следующей процедурой: Sub Macro1() n = InputBox("Input Name ...
Поднять блок вверх — css
Вопрос: Здравствуйте! Хочу поднять блок с картинками выше, но когда задаю слишком большой margin-top то второй ряд просто начинает наезжать сверху на первый и съезжается в ...
SQLJ в Java (Intellij idea) — java oracle jdbc
Вопрос: Подскажите, какую библиотеку нужно скачать, или нечто подобное, чтобы работал import oracle.sqlj.runtime.*; Автор вопроса: DenProg Roman C Здесь находится все для БД Oracle. ...
Виджет приложения в сообществе ВКонтакте — vkontakte-api вконтакте
Вопрос: Недавно у ВКонтакте появилась возможность ставить виджеты в группы (https://vk.com/dev/apps_widgets). Я не понял, как сделать свой виджет? Куда нужно вписывать сам код виджета? Есть ли ...
std::string vs std::wstring в русскоязычном приложении — c++ qt
Вопрос: Поскольку в свое время плавно переехал с чистого C на С++/Qt, то все проблемы unicode остались за кадром, скрытые внутри QString. Теперь при переходе ...
Как правильно проверить ЭП в Java? — java криптография валидация
Вопрос: У меня есть 2 файла - файл подписи(PKCS7) и файл, который был этой подписью подписан. Мой вопрос заключается в том, как можно проверить, что ...
Проблема вращения сцены OpenGL — математика opengl матрицы
Вопрос: Мне нужно вращать сцену вокруг X и Y осей. Проблема в том, что я не могу использовать команды gl.glRotatef(deltaX, 0, 1, 0); gl.glRotatef(deltaY, 1, 0, 0); так ...
Проектирование контакт листа Qt — c++ qt design
Вопрос: Нужно написать контакт лист для мессенджера. Для этого пытаюсь правильно все спроектировать для удобной работы и простого расширения. На данный момент имеется несколько ...

Оставьте ответ

Ваш e-mail не будет опубликован. Обязательные поля помечены *