Как я могу внедрить систему синхронизации потоков, подобную обещанию, в Java 7? - PullRequest
2 голосов
/ 11 февраля 2020

У меня есть метод stati c для получения глобального объекта:

public static Application getApplication() {
    // ...
}

Создание экземпляра Application требует времени для ввода-вывода, поэтому мы создаем его в отдельном потоке. В это время другие потоки могут вызвать getApplication(). Я хочу, чтобы эти потоки блокировались до тех пор, пока не будет создан глобальный экземпляр Application. Я в основном хочу что-то с этой структурой:

private static Application application;
private static PromiseLikeLock lock = new PromiseLikeLock();

public static Application getApplication() {
    lock.await();
    return application;
}

// In thread:
application = new Application();
lock.release();

Со следующим поведением:

  1. Объект lock является конечным автоматом, который либо заблокирован или выпущен . Он начинает блокироваться.
  2. Когда поток выполняет вызов на lock.wait(), если блокировка снята, он продолжает работать как обычно, в противном случае он блокируется.
  3. Когда вызывается lock.release(), блокировка освобождается и все потоки, блокирующие вызов wait(), разблокируются.

Ответы [ 2 ]

3 голосов
/ 11 февраля 2020

Я думаю, что это должно сделать это .... используя Java 7 API.

FutureTask<Application> ft =
       new FutureTask<>(new Callable<Application>() {
                             public Application call() {
                                  return new Application();
                             }});
new Thread(ft).start();

// Somewhere else / later on
Application app = ft.get();

javado c для FutureTask описывает это следующим образом:

Отменяемые асинхронные вычисления. Этот класс предоставляет базовую реализацию Future, с методами для запуска и отмены вычисления, запроса, чтобы увидеть, завершено ли вычисление, и получения результата вычисления. Результат может быть получен только после завершения вычисления; get методы будут блокироваться, если вычисление еще не завершено. ....

A FutureTask может использоваться, чтобы обернуть объект Callable или Runnable. Поскольку FutureTask реализует Runnable, FutureTask может быть передан Executor для выполнения.

И вы также можете передать его в одноразовое использование Thread.


Но, честно говоря, вы не должны писать новый код для Java 7. выше, если вы используете языковые функции Java 8; например, Application::new

1 голос
/ 11 февраля 2020

Это очень похоже на шаблон синглтона, который может быть реализован с использованием перечисления с одним значением:

enum Application{
  INSTANCE;


  private Application(){
    //initialize
  }
  //other methods/fields can go here...
}

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

Разница между этим и решением FutureTask заключается в том, что отдельного потока нет запущен, инициализация вызывается в первом потоке, который фактически использует его.

...