Как прекратить запускать синглтон-класс несколько раз в игровой среде - PullRequest
1 голос
/ 13 октября 2011

У меня есть одноэлементный класс в моем игровом приложении.Этот одноэлементный класс - это длительный процесс, который будет генерировать отчеты из БД, которая потребляет огромное количество памяти.Когда я запускаю свое приложение в режиме разработки, эта функция запускается несколько раз.Я хочу, чтобы эта функциональность запускалась только один раз.Что я должен сделать для этого?

Мой код:

public class DataGridManagerImpl extends ComponentContainer implements DataGridManager {

private static DataGridManager instance = null;

    private DataGridManagerImpl(){
        load();
    }}

@Override
    public void load() {
//Myreports function
}

public static DataGridManager getInstance(){

          if (instance == null){
             instance = new DataGridServiceManagerImpl();
          }

        return instance;
    }
}

В моем файле контроллера внутри функции шаблона

DataGridManager dataGridMgr = DataGridManagerImpl.getInstance();

Если я захожу на страницу, этоснова выполнить функцию загрузки отчетов.

Ответы [ 5 ]

2 голосов
/ 13 октября 2011

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

Вероятно, лучший подход - использовать Запланированное задание . Это запустит процесс в определенное время, и Play гарантирует, что одновременно будет запущен только 1 экземпляр этого процесса, даже если в расписании будет указан другой экземпляр. Допустим, у вас есть процесс, запланированный на каждый час, и процесс занимает 3 часа. Первоначальный процесс будет единственным, выполняющимся в течение 3 часов, пока он не завершится.

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

РЕДАКТИРОВАТЬ при обновлении: во время разработки @OnApplicationStart может выполняться несколько раз, поскольку Play может автоматически перезагружать приложение при внесении определенных изменений кода. Это часть процесса разработки (то же самое, что задание @OnApplicationStart не запустится в Dev, пока сервер не получит запрос).

Поскольку это задание, которое вы хотите выполнить только один раз, вы можете попробовать пропустить его в режиме разработки, используя проверку:

if (Play.mode == Play.Mode.DEV)

Если вам нужно запустить его хотя бы один раз, добавьте URL-адрес только для разработчиков, к которому вы можете обратиться во время разработки, для запуска процесса.

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

ВТОРОЕ РЕДАКТИРОВАНИЕ (в комментариях): Арасу, другая проблема заключается в том, что вы вызываете метод load () при создании объекта. Синглтон не гарантирует, что объект будет построен только один раз. Это гарантирует, что после постройки будет существовать только 1 объект. Но может случиться так, что объект удаляется GC, в этом случае в соответствии с вашим кодом, если вы создадите его снова, тогда вы вызовете load () и повторите обработку.

Лучшее решение - не вызывать «load» для конструктора, а заставить пользователя (вас) вызывать его после получения экземпляра. Альтернативой является установка какого-либо флага в начале загрузки, который определяет, был ли выполнен код. Помните, что Play не имеет состояния, поэтому этот флаг нужно будет сохранить в базе данных.

1 голос
/ 13 октября 2011

Определение синглтона в том, что он может работать только один раз, это практически характер паттерна. Если вам как-то удастся запустить его несколько раз, у вас могут быть ошибки реализации в вашем синглтоне.

Повторно проверьте шаблон синглтона в Википедия .

Edit:

Этот код делает невозможным получение более одного экземпляра. Как бы вы получили более одного?

public class Singleton {
    private static Singleton _instance;

    private Singleton() {  }

    public static synchronized Singleton getInstance() {
            if (null == _instance) {
                    _instance = new Singleton();
            }
            return _instance;
    }
}

Или вы имеете в виду, что вы создаете экземпляр класса Singleton вместо вызова Singleton.getInstance ()?

0 голосов
/ 13 октября 2011

Не знаю, поможет ли это, но вот несколько вещей, которые нужно проверить:

Код в вашем вопросе не является потокобезопасным. Вам не хватает ключевого слова synchronized в getInstance. Это может привести к тому, что конструктор будет вызываться более одного раза разными потоками.

Может ли DataGridManagerImpl загружаться разными загрузчиками классов? Эта статическая переменная instance не является статической для всей JVM, просто является статической для загрузчика классов этого класса.

load - это public. Может ли другой код вызывать этот метод?

0 голосов
/ 13 октября 2011

У меня была такая же проблема в режиме DEV, и я создал модуль для задач, которые я не хочу запускать на каждом @OnApplicationStart.

Хитрость заключается в том, чтобы запустить эти задачи в переопределенном методе onLoad () в модуле:

public void onLoad() 
{
    // tasks to run one time only
}

Метод onLoad () вызывается только один раз, а не каждыйприложение перезапускается.

0 голосов
/ 13 октября 2011

Возможно, чтобы Singleton выполнял трудоемкую обработку и вызывался одновременно двумя разными потоками.Я думаю, что это ситуация здесь.Метод одного и того же объекта Singleton вызывается из программы несколько раз.

Я провел небольшой тест ... два потока вызывают один и тот же объект Singleton, и вот результат

Thread[Thread 1,5,main] internal loop number = 0 Object = example.Singeton@164f1d0d
Thread[Thread 2,5,main] internal loop number = 0 Object = example.Singeton@164f1d0d
Thread[Thread 1,5,main] internal loop number = 1 Object = example.Singeton@164f1d0d

ивот код

package example;

public class Singeton {

private static final Singeton INSTANCE = new Singeton(); 
private Singeton() {}

public static Singeton getInstance(){
    return INSTANCE;
}

public boolean doTimeConsumingThing(){
    for (int i=0; i<10000000;i++){
        System.out.println(Thread.currentThread() + " internal loop number = " + i +  " Object = "  + toString());
    }
    return true;
}
}

 package example;

public class MulThread extends Thread{
public MulThread(String name) {
    super(name);
}
@Override
public void run() {
    while(true){
        Singeton s = Singeton.getInstance();
        System.out.println("Thread " + getId());
        s.doTimeConsumingThing();
    }
}
public static void main(String[] args) {
    MulThread m1 = new MulThread("Thread 1");
    MulThread m2 = new MulThread("Thread 2");
    m1.start();
    m2.start();
}
}

Пожалуйста, исправьте мое мнение выше, если я ошибаюсь.

Следовательно, вам нужна переменная для отслеживания состояния длительной процедуры (т. Е. Логическое значение isRunning) иливремя, когда процедура была вызвана.

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

Надеюсь, это поможет

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