Java:回调到主线程

Java: Callback to main Thread

提问人:PeMa 提问时间:8/23/2022 更新时间:8/23/2022 访问量:449

问:

如何让回调在“主线程”中执行?

@Test
void threadTest() throws InterruptedException {

    System.out.println("main thread:" + Thread.currentThread());

    new Thread(new AsyncTask(this::callback)).start();

    Thread.sleep(1100);
}

private void callback() {
    System.out.println("callback executed in: " + Thread.currentThread());
}

static class AsyncTask implements Runnable{
  private final  Runnable runnable;

    public AsyncTask(Runnable runnable) {
        this.runnable = runnable;
    }

    @Override
    public void run() {
        System.out.println("other thread: " + Thread.currentThread());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        this.runnable.run();
    }
}
Java 多线程 回调

评论

0赞 Mark Rotteveel 8/23/2022
听起来像是 XY 问题。你想达到什么目的?
2赞 Thomas 8/23/2022
SImple:只是不要从生成的线程执行它,而是从主线程执行它。更准确地说:你不能告诉主线程“现在这样做”,但你可以编写你的代码,让它等待一些标志/状态,然后运行“回调”。这可以通过加入生成的线程、阻塞可能返回的期货(虽然不是来自 Runnable)或主动等待设置某些变量来完成。但正如 Mark 所说,这似乎是一个 XY 问题,因此我们需要知道您真正想要的是什么,以便提供具体的帮助。
0赞 PeMa 8/23/2022
实际情况是一个提供反应式管道的库,从代理读取。它将消息包装到具有确认方法的类中。管道允许用户注册在任意线程中执行的异步处理程序,并在他们想要的位置调用确认。消息包装器确认方法是一个回调,必须在订阅代理的同一线程上执行,因为底层客户端不是线程安全的。
0赞 Solomon Slow 8/23/2022
回复,“......必须在同一线程上执行的回调...”就像@Thomas说的,你不能主线程改变它正在做的事情并执行一些任意函数。代码可以在客户端线程上“执行任何操作”的唯一方法是客户端线程调用代码。你能做的最好的事情就是提供一个方法,你的客户端定期他们的“主”线程调用,并让该方法执行任何到期的回调。
0赞 Thomas 8/23/2022
使用响应式处理时,您还需要考虑“非阻塞”。这意味着您不应该“调用”任何线程,而基本上只是为线程提供任务,当它们有容量时可以执行这些任务。这样一来,用户提供的处理程序可能只是一个任务,它将确认任务放入主线程的池中,并且可以携带另一个任务,该任务要放入另一个池中,以便在确认后执行 - 如果需要的话。

答:

1赞 Sergey Tsypanov 8/23/2022 #1

您可以尝试强制执行:callback()ExecutorService

class ConcTest {
    ExecutorService mainExecutor  = Executors.newFixedThreadPool(1);

    @Test
    void threadTest() throws Exception {
        mainExecutor.submit(() -> {
            System.out.println("main thread:" + Thread.currentThread());
            new Thread(new AsyncTask(mainExecutor, this::callback)).start();
            sleep(1100);
        }).get();
    }

    private void callback() {
        System.out.println("callback executed in: " + Thread.currentThread());
    }

    private static void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    static class AsyncTask implements Runnable{
        private final ExecutorService mainExecutor;
        private final Runnable runnable;

        public AsyncTask(ExecutorService mainExecutor, Runnable runnable) {
            this.mainExecutor = mainExecutor;
            this.runnable = runnable;
        }

        @Override
        public void run() {
            System.out.println("other thread: " + Thread.currentThread());
            try {
                Thread.sleep(1000);
                mainExecutor.submit(runnable).get();
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

这将打印

main thread:Thread[pool-1-thread-1,5,main]
other thread: Thread[Thread-0,5,main]
callback executed in: Thread[pool-1-thread-1,5,main]

评论

0赞 PeMa 8/23/2022
谢谢你的回答。实际上,这可以通过提交 .不幸的是,那时我无法访问执行人。但是,我喜欢 .() -> mainExecutor.execute(this::callback)submit(...).get()