У меня есть сервер с несколькими клиентами. Он использует один серверный сокет и два пула потоков для приема и обработки запросов от удаленных клиентов: один пул — для обработки клиентских подключений, а другой — для обработки удаленных задач клиентов. Каждый клиент отправляет асинхронные задачи с уникальным идентификатором задачи (в рамках каждого соединения) и набором параметров. При десериализации задачи сервер ищет соответствующую службу, вызывает для нее заданный метод, оборачивает результат вместе с идентификатором задачи в объект ответа и отправляет его обратно клиенту с помощью ObjectOutputStream
.
Поскольку задачи обрабатываются одновременно, два или более потока могут закончить обработку задач для одного клиента одновременно и попытаться конкурировать за ObjectOutputStream
.
Что происходит дальше? Я имею в виду, пишут ли они свои объекты в выходной поток атомарно или я должен синхронизировать их доступ к ObjectOutputStream
, чтобы не было ситуации, когда один поток пишет половину своего объекта - потом вмешивается другой поток и... Объект Франкенштейна будет отправлен клиенту.
import java.io.*;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.*;
public class Server {
private final ExecutorService connExecutor = Executors.newCachedThreadPool();
private final ExecutorService tasksExecutor = Executors.newCachedThreadPool();
public void start() {
try (ServerSocket socket = new ServerSocket(2323);) {
while (true) {
try (Socket conn = socket.accept()) {
connExecutor.execute(() -> {
try (ObjectInputStream in = new ObjectInputStream(conn.getInputStream());
ObjectOutputStream out = new ObjectOutputStream(conn.getOutputStream())) {
while (true) {
RemoteTask task = (RemoteTask) in.readObject();
tasksExecutor.execute(() -> {
handleTask(task, out);
});
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
});
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void handleTask(RemoteTask task, ObjectOutputStream out) {
RemoteAnswer answer = new RemoteAnswer();
// unwrap remote task
// lookup local service
// invoke task's method
// wrap result into remote answer
// send answer to the client
try {
out.writeObject(answer);
} catch (IOException e) {
e.printStackTrace();
}
}
}