Многопоточность в Java - просто - PullRequest
1 голос
/ 06 ноября 2011

У меня простой вопрос, как преобразовать этот сервер в многопоточный, поскольку теперь он работает только с одним клиентом. Какая часть должна идти в run () part:)?

ServerSocket listener = new ServerSocket(9090);
System.out.println("server\n");
try {
    while (true) {
        Socket socket = listener.accept();
        System.out.println(socket+" " + "welcome\n");
        try { 
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            out.println(new Date().toString());
            BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String answer = input.readLine();
            System.out.println(answer);
            if("hej".equals(answer)){
                System.out.println("Sacrafice accepted");
            }
        } finally {
            socket.close();
        }
    }
} finally {
    listener.close();
}

Ответы [ 4 ]

2 голосов
/ 06 ноября 2011

Использовать один поток на каждое клиентское соединение.Основной поток логики в таком мультиклиентском сервере таков:

while (true) {
    accept a connection ;
    get a thread from pool to deal with the client ;
}
1 голос
/ 06 ноября 2011

Обслуживание каждого соединения, возвращенного из accept, должно идти в отдельный поток, т. Е. В метод run() должно быть перенесено следующее:

System.out.println(socket + " " + "welcome\n");
try {
    PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
    out.println(new Date().toString());
    BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    String answer = input.readLine();
    System.out.println(answer);
    if ("hej".equals(answer)) {
        System.out.println("Sacrafice accepted");
    }
}
finally {
    socket.close();
}

Конечно, вам нужно добавить код, который создает поток. Поскольку создание потоков является дорогостоящей задачей, а потоки можно многократно использовать, лучше всего создать несколько рабочих потоков в пуле заранее во время инициализации, а затем извлекать рабочие потоки из пула только после того, как вы примете соединение и нуждаетесь в потоке для его обслуживания. При разработке приложения вы можете обнаружить, что добавление некоторой логики для настройки размера пула потоков во время выполнения на основе нагрузки является хорошей идеей, но вам, вероятно, следует отказаться от этого на текущем этапе и просто использовать элемент конфигурации (например, командную строку). option или static final) для установки начального размера пула потоков. Вы можете найти реализации пула потоков в java.util.concurrent .

Если вы сделаете это, метод потока run() будет очень просто ждать в цикле новых задач, и каждый раз, когда он получает задачу, он должен запускать метод этой задачи run(). Приведенный выше код должен быть помещен в метод задачи run(). Таким образом вы отделите потоки от задач и, следовательно, убедитесь, что потоки остаются многократно используемыми. Потокам также понадобится метод для получения задач, и этот метод должен быть потокобезопасным. Вы можете использовать одну из реализаций очереди из java.util.concurrent для хранения задач в ваших потоках между временем, которое они передают в поток для обслуживания, и временем, когда они удаляются из очереди run() метода потока для их фактического запуска.

Такое разделение потоков и задач является еще одним случаем, когда добавление еще одного уровня косвенности решает важную проблему разработки программного обеспечения .

1 голос
/ 06 ноября 2011

Часть после listener.accept(). Как только основной поток получил соединение от клиента, пусть другой поток (предпочтительно объединенный в пул) обрабатывает связь с этим клиентом, чтобы основной поток мог принять другой.

Используйте для этого ThreadPoolExecutor: каждый раз, когда соединение принято, создайте новый экземпляр Runnable и заставьте его исполниться исполнителем.

0 голосов
/ 06 ноября 2011

создайте класс serverThread, унаследованный от Thread, чтобы объявить конструктор, который принимает сокет в методе Run (), скопировать всю попытку {} catch {}

переведенный Google

...