Eclipse RAP Мультиклиент, но один серверный поток

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

Я хотел бы иметь серверную часть (с доступом к базам данных и прочее), которая представляет собой однократное выполнение, чтобы гарантировать, что она имеет глобальные знания обо всех транзакциях и что запросы от клиентов выполняются последовательно, а не параллельно.

В настоящее время я получаю доступ к контексту приложения следующим образом из пользовательского интерфейса:

synchronized( MyServer.class ) {
    ApplicationContext appContext = RWT.getApplicationContext();

    MyServer myServer = (MyServer) appContext.getAttribute("myServer");
        if (myServer == null){
          myServer = new MyServer();
          appContext.setAttribute("myServer", myServer);
        }
    myServer.doSomething(RWTUtils.getSessionID());
}

Даже если я получу доступ к объекту myServer и инициирую запросы, выполнение все равно будет выполняться в потоке пользовательского интерфейса.

На данный момент единственный способ обеспечить последовательность — использовать synchronized следующим образом на моем сервере.

public class MyServer {
    String text = "";

    public void doSomething(String string) {
        try {
            synchronized (this) {
                System.out.println("doSomething - start :" + string);
                text += "[" + string + "]";
                System.out.println("text: " + (text));
                Thread.sleep(10000);
                System.out.println("text: " + (text));
                System.out.println("doSomething - stop :" + string);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Есть ли лучший способ не управлять синхронизацией потоков самостоятельно?

Любая помощь приветствуется

EDIT: Чтобы лучше объяснить, вот что я имею в виду. Либо я доверяю базе данных правильно обрабатывать множественные запросы, и мне приходится синхронно обрабатывать некоторые другие знания для обмена информацией между клиентами (пример A), либо я нахожу решение, в котором другой поток обрабатывает и то, и другое (пример B), знание и базу данных. Конечно, проблема здесь в том, что один клиент может блокировать другие, но это можно сделать с помощью фоновых потоков для длинных действий, большинство из них не будет проблемой. Мой первоначальный вопрос заключался в том, может быть, уже есть какой-то конкретный поток области применения, который выполняет пример B, или пример A действительно подходит?

Потоки Eclipse RAP: как обращаться с общими знаниями и доступом к базе данных?

Заключение (на данный момент)

По сути, вариант A) — правильный путь. Для доступа к базе данных потребуется пул соединений, а для общей информации — продуманная синхронизация ключевых объектов. Основное внимание должно быть уделено проектированию базы данных и синхронизации объектов, чтобы два клиента не могли одновременно записывать несовместимые данные (например, записывать противоречащие друг другу записи, которые делают результат зависимым от порядка записи).


person Jarod    schedule 18.02.2016    source источник


Ответы (1)


Прежде всего, способ, которым вы создаете MyServer в первом фрагменте, не является потокобезопасным. Вероятно, вы создадите более одного экземпляра MyServer.

Вам нужно синхронизировать создание MyServer, например так:

synchronized( MyServer.class ) {
  MyServer myServer = (MyServer) appContext.getAttribute("myServer");
  if (myServer == null){
    myServer = new MyServer();
    appContext.setAttribute("myServer", myServer);
  }
}

См. также этот пост Как реализовать потокобезопасную ленивую инициализацию? для другие возможные решения.

Кроме того, ваш код вызывает doSomething() в клиентском потоке (то есть в потоке пользовательского интерфейса), что заставит каждого клиента ждать, пока не будут обработаны ожидающие запросы других клиентов. Пользовательский интерфейс клиента перестанет отвечать на запросы.

Чтобы решить эту проблему, ваш код должен вызывать doSomething() (или любую другую длительную операцию в этом отношении) из фонового потока (см. также Темы в RAP)

Когда фоновый поток завершится, вы должны использовать Server Push для обновления пользовательского интерфейса.

person Rüdiger Herrmann    schedule 18.02.2016
comment
Спасибо за ответ. Да, вы правы, мой вызов myserver небезопасен, я просто написал это, чтобы проверить концепцию, это не обычный способ сделать это :) В любом случае, я вижу много примеров того, как вызывать поток пользовательского интерфейса из background, но я не знаю, как выполнить фоновое действие из пользовательского интерфейса. - person Jarod; 18.02.2016
comment
См. пример кода в главе Server Push, там все есть - person Rüdiger Herrmann; 18.02.2016
comment
Ах да, ладно, я наблюдал за темой bgThread = new Thread( bgRunnable ); линии. Итак, в основном, чтобы получить мой сервер с одним потоком, мне нужно было бы только поделиться этим конкретным потоком между клиентами, правильно ли это, по вашему мнению? Спасибо за помощь! - person Jarod; 18.02.2016
comment
PS: или еще проще сделать MyServer Runnable и запускать bgThread при запуске сервера. - person Jarod; 18.02.2016
comment
Серверу не нужен поток. Каждый клиент, который вызывает сервер, должен использовать дополнительный поток, чтобы пользовательский интерфейс оставался отзывчивым. Ваш пример будет работать даже без потоков. Однако он будет блокировать пользовательский интерфейс каждого клиента до тех пор, пока вызов server.doSomething() не вернется. - person Rüdiger Herrmann; 18.02.2016
comment
Хм, ладно, но если у меня есть доступ к базе данных, не будет ли проблемой, если несколько клиентов будут выполнять запросы по одному и тому же соединению параллельно? - person Jarod; 18.02.2016
comment
Обычно да. Если это так, вам нужно использовать отдельные/объединенные соединения. - person Rüdiger Herrmann; 18.02.2016
comment
Несмотря на то, что это не совсем то решение, которое я ожидал/надеялся :) (ленивый вариант B) на моем изображении), я все равно проверю соответствующие входные данные и комментарии. Я добавил вывод к своему сообщению, чтобы обобщить свои мысли, основанные на ваших предложениях. Спасибо! - person Jarod; 19.02.2016