Java中如何异步调用方法

发布于 2024-08-13 05:11:02 字数 1220 浏览 8 评论 0原文

我最近一直在研究 Go 的 goroutines 并认为有类似的东西会很好在爪哇。据我搜索,并行化方法调用的常见方法是执行以下操作:

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

这不是很优雅。 有更好的方法吗? 我在项目中需要这样的解决方案,因此我决定围绕异步方法调用实现我自己的包装器类。

我在 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 的类,并执行一些反射工作来获取正确的方法对象并调用它。

我想要一些关于我的小库以及关于在 Java 中进行像这样的异步方法调用的主题的意见。安全吗?已经有更简单的方法了吗?

I've been looking at Go's goroutines lately and thought it would be nice to have something similar in Java. As far as I've searched the common way to parallelize a method call is to do something like:

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

Thats not very elegant. Is there a better way of doing this? I needed such a solution in a project so I decided to implement my own wrapper class around a async method call.

I published my wrapper class in J-Go. But I don't know if it is a good solution. The usage is simple:

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

or less verbose:

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

Internally I'm using a class that implements Runnable and do some Reflection work to get the correct method object and invoking it.

I want some opinion about my tiny library and on the subject of making async method calls like this in Java. Is it safe? Is there already a simplier way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

谁的年少不轻狂 2024-08-20 05:11:02

我刚刚发现有一种更干净的方法可以做到这一点

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

(至少在 Java 8 中),您可以使用 lambda 表达式将其缩短为:

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

就像在 JS 中创建函数一样简单!

I just discovered that there is a cleaner way to do your

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

(At least in Java 8), you can use a lambda expression to shorten it to:

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

As simple as making a function in JS!

逆蝶 2024-08-20 05:11:02

Java 8引入了CompletableFuture,可在java.util.concurrent.CompletableFuture包中使用,可用于进行异步调用:

CompletableFuture.runAsync(() -> {
    // method call or code to be asynch.
});

Java 8 introduced CompletableFuture available in package java.util.concurrent.CompletableFuture, can be used to make a asynch call :

CompletableFuture.runAsync(() -> {
    // method call or code to be asynch.
});
美羊羊 2024-08-20 05:11:02

您可能还希望考虑类java.util.concurrent.FutureTask

如果您使用的是 Java 5 或更高版本, FutureTask 是“可取消的异步计算”的交钥匙实现。

java.util.concurrent 包中提供了更丰富的异步执行调度行为(例如 ScheduledExecutorService),但是 FutureTask 可能拥有所有您需要的功能。

我什至会说,自从 FutureTask 可用以来,不再建议使用您给出的第一个代码模式作为示例。 (假设您使用的是 Java 5 或更高版本。)

You may wish to also consider the class java.util.concurrent.FutureTask.

If you are using Java 5 or later, FutureTask is a turnkey implementation of "A cancellable asynchronous computation."

There are even richer asynchronous execution scheduling behaviors available in the java.util.concurrent package (for example, ScheduledExecutorService), but FutureTask may have all the functionality you require.

I would even go so far as to say that it is no longer advisable to use the first code pattern you gave as an example ever since FutureTask became available. (Assuming you are on Java 5 or later.)

隔岸观火 2024-08-20 05:11:02

我不喜欢为此使用反射的想法。
不仅在某些重构中丢失它很危险,而且它也可能被 SecurityManager 拒绝。

与 java.util.concurrent 包中的其他选项一样,FutureTask 是一个不错的选择。
我最喜欢的简单任务:

    Executors.newSingleThreadExecutor().submit(task);

比创建线程短一点(任务是 Callable 或 Runnable)

i don't like the idea of using Reflection for that.
Not only dangerous for missing it in some refactoring, but it can also be denied by SecurityManager.

FutureTask is a good option as the other options from the java.util.concurrent package.
My favorite for simple tasks:

    Executors.newSingleThreadExecutor().submit(task);

little bit shorter than creating a Thread (task is a Callable or a Runnable)

哆兒滾 2024-08-20 05:11:02

您可以使用 CompletableFuture 的 Java8 语法,这样您就可以根据调用异步函数的结果执行额外的异步计算。

例如:

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

更多详细信息可以在这篇文章中找到

You can use the Java8 syntax for CompletableFuture, this way you can perform additional async computations based on the result from calling an async function.

for example:

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

More details can be found in this article

清浅ˋ旧时光 2024-08-20 05:11:02

您可以使用 @Async 注释http://aspects.jcabi.com" rel="noreferrer">jcabi-aspects 和 AspectJ:

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

当您调用 save() 时,一个新线程启动并执行其主体。您的主线程将继续执行,无需等待 save() 的结果。

You can use @Async annotation from jcabi-aspects and AspectJ:

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

When you call save(), a new thread starts and executes its body. Your main thread continues without waiting for the result of save().

春花秋月 2024-08-20 05:11:02

Java 还提供了一种调用异步方法的好方法。在java.util.concurrent中,我们有ExecutorService来帮助做同样的事情。像这样初始化你的对象 -

 private ExecutorService asyncExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

然后调用函数 -

asyncExecutor.execute(() -> {

                        TimeUnit.SECONDS.sleep(3L);}

Java also provides a nice way of calling async methods. in java.util.concurrent we have ExecutorService that helps in doing the same. Initialize your object like this -

 private ExecutorService asyncExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

and then call the function like-

asyncExecutor.execute(() -> {

                        TimeUnit.SECONDS.sleep(3L);}
三生池水覆流年 2024-08-20 05:11:02

您可以为此使用 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/

You can use Future-AsyncResult for this.

@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);
}

Reference: https://spring.io/guides/gs/async-method/

子栖 2024-08-20 05:11:02

您可以使用 AsyncFunc 来自 Cactoos

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

它将在后台执行,结果将在 get() 作为 Future

You can use AsyncFunc from Cactoos:

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

It will be executed at the background and the result will be available in get() as a Future.

和影子一齐双人舞 2024-08-20 05:11:02

Java 21+:

Thread.ofVirtual().start(() -> {
    // Some work
});

或者(如果您由于某种原因不需要虚拟线程):

Thread.ofPlatform().start(() -> {
    // Some work
});

Java 21+:

Thread.ofVirtual().start(() -> {
    // Some work
});

Or (if you don't want a virtual thread for some reason):

Thread.ofPlatform().start(() -> {
    // Some work
});
白日梦 2024-08-20 05:11:02

这可能不是一个真正的解决方案,但现在 - 在 Java 8 中 - 您可以使用 lambda 表达式使此代码看起来至少好一点。

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

您甚至可以在一行中完成此操作,并且仍然具有良好的可读性。

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

It's probably not a real solution, but now - in Java 8 - You can make this code look at least a little better using lambda expression.

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

And You could even do this in one line, still having it pretty readable.

new Thread(() -> x.matches("something")).start();
情深缘浅 2024-08-20 05:11:02

这并不是真正相关,但如果我要异步调用一个方法,例如 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();
}

我已经测试过它并且它有效。只是认为如果其他人只是为了“异步方法”而来,这可能会对他们有所帮助。

This is not really related but if I was to asynchronously call a method e.g. matches(), I would use:

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);
        }

    });
}

Then to call the asynchronous method I would use:

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

I have tested this and it works. Just thought it may help others if they just came for the "asynchronous method".

执手闯天涯 2024-08-20 05:11:02

EA 还为 Async-Await 创建了一个不错的库: https://github.com/electronicarts/ea -async

来自自述文件:

使用 EA Async

import static com.ea.async.Async.await;
import static java.util.concurrent.CompletableFuture.completedFuture;

public class Store
{
    public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
    {
        if(!await(bank.decrement(cost))) {
            return completedFuture(false);
        }
        await(inventory.giveItem(itemTypeId));
        return completedFuture(true);
    }
}

不使用 EA Async

import static java.util.concurrent.CompletableFuture.completedFuture;

public class Store
{
    public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
    {
        return bank.decrement(cost)
            .thenCompose(result -> {
                if(!result) {
                    return completedFuture(false);
                }
                return inventory.giveItem(itemTypeId).thenApply(res -> true);
            });
    }
}

There is also nice library for Async-Await created by EA: https://github.com/electronicarts/ea-async

From their Readme:

With EA Async

import static com.ea.async.Async.await;
import static java.util.concurrent.CompletableFuture.completedFuture;

public class Store
{
    public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
    {
        if(!await(bank.decrement(cost))) {
            return completedFuture(false);
        }
        await(inventory.giveItem(itemTypeId));
        return completedFuture(true);
    }
}

Without EA Async

import static java.util.concurrent.CompletableFuture.completedFuture;

public class Store
{
    public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
    {
        return bank.decrement(cost)
            .thenCompose(result -> {
                if(!result) {
                    return completedFuture(false);
                }
                return inventory.giveItem(itemTypeId).thenApply(res -> true);
            });
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文