Как исправить «Эта операция может быть причиной тупика» - PullRequest
1 голос
/ 20 октября 2019

Когда я вызываю sendDM () во второй раз, я получаю предупреждение о взаимоблокировке. Как я могу это исправить?

Я использую JDA Api, и я пытаюсь получить сообщение, которое я отправил с RestAction .complete ()

    private void start(){

        sendDM(getP1().getUser());
        sendDM(getP2().getUser());

        EmbedBuilder embedBuilder = new EmbedBuilder();
        textChannel.sendMessage(p1.getUser().getAsMention() + " " + p2.getUser().getAsMention()).queue();
        textChannel.sendMessage(embedBuilder.setTitle("**Match has started - #" + getGameId() + "**")
                        .addField("Info", "ID: " + getGameId() + "\nMap: 7189-0031-5500" + "\nStatus: " + getStatus().toString(),true)
                        .addField("Player 1", p1.getUser().getAsMention() + " - Host", false)
                        .addField("Player 2", p2.getUser().getAsMention(), false)
                        .addField("Lobby", textChannel.getAsMention(), false)
                        .setFooter("Both participants will receive a Private Message where they can submit match results", null).build())
                .queue();


    }

    private void sendDM(User user){

        EmbedBuilder embedBuilder = new EmbedBuilder();
        user.openPrivateChannel().queue((channel) ->
        {
            channel.sendMessage(p1.getUser().getAsMention() + " " + p2.getUser().getAsMention()).queue();
            Message message = channel.sendMessage(embedBuilder.setTitle("**Match has started - #" + getGameId() + "**")
                    .addField("Info", "ID: " + getGameId() + "\nMap: 7189-0031-5500" + "\nStatus: " + getStatus().toString(),true)
                    .addField("Player 1", p1.getUser().getAsMention() + " - Host", false)
                    .addField("Player 2", p2.getUser().getAsMention(), false)
                    .addField("Lobby", textChannel.getAsMention(), false)
                    .addField("**If you win**", ":white_check_mark:", true)
                    .addField("**If you loose**", ":x:", true)
                    .setFooter("Both participants will receive a Private Message where they can submit match results", null).build())
                    .complete();
            message.addReaction("\u274C").complete();
            message.addReaction("\u2705").complete();

        });

    }

Я ожидаю, что он просто вернетСообщение, но я получаю эту ошибку:

[ForkJoinPool.commonPool-worker-1] ERROR net.dv8tion.jda.api.requests.RestAction - Encountered error while processing success consumer
java.lang.IllegalStateException: Preventing use of complete() in callback threads! This operation can be a deadlock cause
    at net.dv8tion.jda.internal.requests.RestActionImpl.complete(RestActionImpl.java:187)
    at net.dv8tion.jda.api.requests.RestAction.complete(RestAction.java:357)
    at match.Match.lambda$sendDM$0(Match.java:71)
    at net.dv8tion.jda.api.requests.Request.lambda$onSuccess$0(Request.java:83)
    at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

Ответы [ 2 ]

1 голос
/ 20 октября 2019

Существует только один поток обратного вызова, который используется для выполнения обратных вызовов. *

Ваш вызов user.openPrivateChannel().queue((channel) -> {...} выполняется в этом отдельном потоке обратного вызова.

Ваш вызов message.addReaction("\u274C").complete(); блокируется до тех пор, показавершен, но он будет работать в том же единственном потоке обратного вызова, который уже занят выполнением внешнего обратного вызова, который хочет выполнить complete() ... вы видите проблему. Это обнаруживается под капотом, и возникает исключение, чтобы предотвратить возникновение этого тупика.

Просто используйте вместо него message.addReaction("\u274C").queue();. queue() немедленно возвращается, так что поток обратного вызова получает шанс запустить его после завершения внешнего обратного вызова.

См. Документы для complete() и queue().


* См. Эти документы по устранению неполадок здесь :

Поскольку мы решили использовать однопоточный пул (1), у нас есть толькоодин поток для выполнения обратных вызовов. Этот поток используется первым обратным вызовом (2) и не может использоваться для второго обратного вызова (3).

По этой причине мы просто не разрешаем использовать complete() в любых потоках обратного вызова вообще. Если вы используете обратные вызовы, вы должны использовать queue().

(Copyright 2015-2019 Austin Keener, Michael Ritter, Florian Spieß)

0 голосов
/ 20 октября 2019

Вы должны решить, придерживаться ли просто блокировки или просто асинхронно. Я рекомендую держать его асинхронным и использовать submit(), чтобы избежать вложенных обратных вызовов:

user.openPrivateChannel().submit() // CompletableFuture<PrivateChannel>
    .thenCompose((channel) -> {
        channel.sendMessage(ignored).queue();
        return channel.sendMessage(embed).submit(); // CompletableFuture<Message>
    })
    .thenCompose((message) -> CompletableFuture.allOf( // combine 2 futures to 1
        message.addReaction(a).submit(),
        message.addReaction(b).submit())) // CompletableFuture<Void>
    .whenComplete((v, error) -> {
        if (error != null) error.printStackTrace(); // handle errors
    });

Как правильно указал Макс Воллмер, вы не можете использовать complete() внутри queue() обратный вызов, потому что он заблокирует поток обратного вызова. complete() работает, работая в том же потоке, который используется для обработки обратного вызова, который в данный момент занят ожиданием завершения полного вызова, который ожидает завершения обратного вызова очереди, это бесконечный цикл, который никогда не будет завершен. [1]

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