Как избежать исключений параллелизма при создании службы XML-RPC, которая должна обмениваться глобальными данными между потоками - PullRequest
0 голосов
/ 03 ноября 2011

Я создаю сервер XML-RPC на Java с использованием библиотеки Redstone XML-RPC . Сервер отвечает за запуск команд в системе и затем ответный ответ. Например, пользователь говорит серверу сделать ls, и сервер возвращает список файлов. Точно так же пользователь может выполнять асинхронные команды и возвращать идентификатор процесса для последующего запроса. Все эти методы относятся к одному большому подклассу Command, который является частью основного класса RPCServlet extends XmlRpcServlet.

Для достижения этой цели я сохраняю глобальную хэш-карту instances. Когда приходит асинхронная команда, я создаю экземпляр класса ProcessManager, который расширяет поток. Затем я добавляю его в хэш instances, запускаю его и возвращаю идентификатор пользователю. Когда приходит запрос на этот идентификатор, я просматриваю его в глобальном хэше и возвращаю либо его полное, либо частичное состояние (в зависимости от того, завершен он или нет).

Это работает нормально, когда это просто один запрос за другим, но когда вы действительно начинаете обрабатывать его множеством запросов, работающих с глобальным хешем instances, он получает исключения параллелизма.

Теперь вот мои точки смущения:

  • Когда приходит запрос, создается ли новый объект класса Command или это один объект, который сидит там вечно, принимая команды? Исходя из этого, как каждый запрос видит глобальный хэш instances? Это мой код инициализации

    открытый класс RPCServlet расширяет XmlRpcServlet {

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        super.init(servletConfig);  
        getXmlRpcServer().addInvocationHandler("Command", new Command(instances));  
    }
    

    }

  • Когда я пытаюсь решить проблему исключений параллелизма, я использую syncronized ИЛИ ConcurrentHashMap вместо HashMap. В любом случае, я в этом тупике. Почему это может быть?

  • Куда должен идти мой глобальный HashMap экземпляров? В RPCServlet? его подкласс Command?

Вот как я сталкиваюсь с этими исключениями параллелизма:

  1. Я создаю кучу асинхронных команд, а затем пытаюсь убить их всех
  2. Я запускаю множество разных клиентов, которые делают это, и это неизбежно приведет к параллельному исключению.

Вот как выглядит asyncCmd :

public HashMap asyncCmd(XmlRpcStruct struct) throws XmlRpcFault {
            HashMap hash;
            if (struct.containsKey("command")) {
                ProcessManager proc = new ProcessManager(struct);
                boolean validInput = proc.readInHashValues();
                if (!validInput) {
                    throw new XmlRpcFault(400, proc.procResult.getTopError());
                }
                int id = proc.objectId;

                instances.put(id, proc);

                proc.start();
                String a;
                if ((a = proc.procResult.getTopError()) != null) {
                    throw new XmlRpcFault(500, a);
                }

                hash = new HashMap();
                hash.put("id", id);
                return hash;
            } else {
                throw new XmlRpcFault(400, "Unable to find a command");
            }
        }

KillAll:

public HashMap killAll() throws XmlRpcFault {
            HashMap retHash = new HashMap();

            int length = instances.values().size();
            if (length > 0) {
                Set keys = instances.keySet();
                for (Object key : keys) {
                    retHash.put(key, killAllKiller(Integer.parseInt(key.toString())));
                }
                //Since we killed all procs, suggest a GC as well
                instances.clear();
                System.gc();


                return retHash;
            } else {
                throw new XmlRpcFault(404, "No processes running");
            }

        }

1 Ответ

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

Позвольте мне предложить другую альтернативу

  • После получения запроса поместите команду и идентификатор в Очередь (обертывание в объекте) и верните идентификатор вuser
  • Создайте ThreadPoolExecutor , который будет получать команды из очереди, выполнять их и помещать результаты в ConcurrentHashMap
  • . Затем клиенты будутполучить доступ только к карте результатов

Таким образом, между новыми запросами и результатами не будет конфликта.

Я бы поместил эту карту в контекст сервлета, который является естественным местомсохранить переменные уровня приложения.

...