Должен ли я синхронизировать ObjectOutputStream.writeObject (Object)? - PullRequest
0 голосов
/ 21 ноября 2019

У меня есть сервер с несколькими клиентами. Он использует один сокет сервера и два пула потоков для получения и обработки запросов от удаленных клиентов: один пул - для обработки клиентских подключений, а другой - для обработки удаленных задач клиентов. Каждый клиент отправляет асинхронные задачи с уникальным идентификатором задачи (в пределах каждого соединения) и набором параметров. После десериализации задачи сервер ищет соответствующую службу, вызывает для нее заданный метод, оборачивает результат вместе с идентификатором задачи в объект ответа и отправляет его обратно клиенту, используя 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();
        }
    }
}

1 Ответ

0 голосов
/ 21 ноября 2019

Практическое правило. Если в документации не указано, что определенный класс является поточно-ориентированным, это, вероятно, не так. Безопасность потоков явно является «преднамеренным качеством» (намек на сообщение в блоге Романа Елизарова , одного из дизайнеров языка Kotlin) и поэтому должно всегда упоминаться.

Однако, если вы все ещене зная, обеспечивает ли класс библиотеки SE SE потокобезопасность или нет (как можно было бы упомянуть в другом месте, например, в документации суперкласса), вы также можете просто взглянуть на исходный код типа. Как видите, , ObjectOutputStream не реализует никаких механизмов синхронизации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...