Подтвердить что ты не робот

Как асинхронно вызывать метод в Java

Я смотрел Go goroutines в последнее время и подумал, что было бы неплохо иметь что-то подобное в Java. Насколько я обыскал обычный способ распараллеливать вызов метода, нужно сделать что-то вроде:

final String x = "somethingelse";
new Thread(new Runnable() {
           public void run() {
                x.matches("something");             
    }
}).start();

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

Я опубликовал свой класс-оболочку в J-Go. Но я не знаю, является ли это хорошим решением. Использование прост:

SampleClass obj = ...
FutureResult<Integer> res = ...
Go go = new Go(obj);
go.callLater(res, "intReturningMethod", 10);         //10 is a Integer method parameter
//... Do something else
//...
System.out.println("Result: "+res.get());           //Blocks until intReturningMethod returns

или менее подробный:

Go.with(obj).callLater("myRandomMethod");
//... Go away
if (Go.lastResult().isReady())                //Blocks until myRandomMethod has ended
    System.out.println("Method is finished!");

Внутри я использую класс, который реализует Runnable и выполняет некоторую работу Reflection, чтобы получить правильный объект метода и вызвать его.

Я хочу получить некоторое мнение о моей крошечной библиотеке и о том, как на Java вызывать вызовы метода async. Это безопасно? Есть ли более простой способ?

4b9b3361

Ответ 1

Я только что обнаружил, что есть более чистый способ сделать ваш

new Thread(new Runnable() {
    public void run() {
        //Do whatever
    }
}).start();

(по крайней мере, в Java 8), вы можете использовать лямбда-выражение, чтобы сократить его до:

new Thread(() -> {
    //Do whatever
}).start();

Так же просто, как сделать функцию в JS!

Ответ 2

Вы также можете рассмотреть класс java.util.concurrent.FutureTask.

Если вы используете Java 5 или более позднюю версию, FutureTask - это реализация "подстановочного асинхронного вычисления" под ключ.

В пакете java.util.concurrent существует еще более богатое асинхронное поведение планирования выполнения (например, ScheduledExecutorService), но FutureTask может иметь все необходимые функции.

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

Ответ 3

Мне не нравится идея использования Reflection для этого.
Не только опасно для его отсутствия в некоторых рефакторингах, но также может быть отказано SecurityManager.

FutureTask является хорошим вариантом в качестве других опций из пакета java.util.concurrent.
Мой любимый для простых задач:

    Executors.newSingleThreadExecutor().submit(task);

маленький бит короче, чем создание потока (задача - это Callable или Runnable)

Ответ 4

Вы можете использовать @Async аннотация из jcabi-аспекты и AspectJ:

public class Foo {
  @Async
  public void save() {
    // to be executed in the background
  }
}

Когда вы вызываете save(), начинается новый поток и выполняется его тело. Ваш основной поток продолжается, не дожидаясь результата save().

Ответ 5

Для этого вы можете использовать Future-AsyncResult.

@Async
public Future<Page> findPage(String page) throws InterruptedException {
    System.out.println("Looking up " + page);
    Page results = restTemplate.getForObject("http://graph.facebook.com/" + page, Page.class);
    Thread.sleep(1000L);
    return new AsyncResult<Page>(results);
}

Ссылка: https://spring.io/guides/gs/async-method/

Ответ 6

Вы можете использовать синтаксис Java8 для CompletableFuture, таким образом вы можете выполнять дополнительные вычисления async на основе результата вызова функции async.

например:

 CompletableFuture.supplyAsync(this::findSomeData)
                     .thenApply(this:: intReturningMethod)
                     .thenAccept(this::notify);

Более подробную информацию можно найти в этой статье

Ответ 7

На самом деле это не так, но если я должен асинхронно вызывать метод, например. matches(), я бы использовал:

private final static ExecutorService service = Executors.newFixedThreadPool(10);
public static Future<Boolean> matches(final String x, final String y) {
    return service.submit(new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            return x.matches(y);
        }

    });
}

Затем для вызова асинхронного метода я бы использовал:

String x = "somethingelse";
try {
    System.out.println("Matches: "+matches(x, "something").get());
} catch (InterruptedException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
}

Я тестировал это, и он работает. Просто подумал, что это может помочь другим, если они просто пришли для "асинхронного метода".

Ответ 8

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

final String x = "somethingelse";
new Thread(() -> {
        x.matches("something");             
    }
).start();

И вы даже можете сделать это в одной строке, все еще имея его довольно читаемым.

new Thread(() -> x.matches("something")).start();

Ответ 9

Вы можете использовать AsyncFunc из Cactoos:

boolean matches = new AsyncFunc(
  x -> x.matches("something")
).apply("The text").get();

Он будет выполнен в фоновом режиме, и результат будет доступен в get() как Future.