首页 > 解决方案 > 循环功能在开始时冻结

问题描述

我正在为我的 Minecraft 服务器制作一个插件,它每 5 秒根据在线玩家的数量更新一个 API。每次服务器启动时,它都会在启用插件时卡住。

这是功能:

public static void playerListLoop(String status, int onlinePlayers) {

        Boolean on = true;

        try {
            while (on = true) {

                try {
                    URL url = new URL("http://192.168.1.14:3000");
                    connection = (HttpURLConnection) url.openConnection();

                    connection.setRequestMethod("POST");
                    connection.setConnectTimeout(5000);
                    connection.setReadTimeout(5000);
                    connection.setRequestProperty("Content-Type", "application/json");
                    connection.setRequestProperty("x-_id", "518747784");
                    connection.setRequestProperty("x-api-key", "7");
                    connection.setDoOutput(true);
                    String urlParameters = "{\"survival\": {\"status\": \"" + status + "\", \"players\": \"" + onlinePlayers + "\"}}";
                    byte[] postData = urlParameters.getBytes(StandardCharsets.UTF_8);

                    try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())){
                        wr.write(postData);
                    }

                    StringBuilder content;

                    try (BufferedReader br = new BufferedReader(
                            new InputStreamReader(connection.getInputStream()))) {
                        String line;
                        content = new StringBuilder();

                        while ((line = br.readLine()) != null) {
                            content.append(line);
                            content.append(System.lineSeparator());
                        }
                    }

                } catch (ProtocolException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    connection.disconnect();
                }
                Thread.sleep(5 * 1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
}

提前致谢!

标签: javawhile-loopminecraft

解决方案


就像@Amongalen 说你的方法playerListLoop()是一个阻塞操作。看,你开始了一个while循环,但你的代码中的循环永远持续下去,因为你的on变量既没有改变,也没有类似break;. 这意味着您的插件会卡在这种方法中。

您需要做的是创建一个新线程并让您的循环在该线程中运行,或者(以及我会推荐的)您使用BukkitScheduler预构建到 Spigot。


同步任务

首先我们保存 id,这样我们就可以再次取消任务:

int taskID;

然后我们创建我们的任务:

  • 为此,您需要一个扩展类的实例JavaPlugin
  • 我在这里使用了一个 lambda 表达式,但你也可以引用一个方法。
  • 在这种情况下,0 是游戏时间的延迟
  • 而 100 是每个循环之间的滴答时间(1 秒 = 20 滴答)
taskID = Bukkit.getScheduler().scheduleSyncRepeatingTask(YourClass.instance, () -> {
    // update your API
}, 0, 100);

要取消您的任务,请执行以下操作:

Bukkit.getScheduler().cancelTask(taskID);

异步任务

如果你希望你的任务是异步的,你需要做一些不同的事情。

这次我们使用BukkitTask界面保存我们的任务:

BukkitTask task;

然后它与同步任务非常相似:

task = Bukkit.getScheduler().runTaskTimerAsynchronously(YourClass.instance, () -> {
    // update your API
}, 0, 100);

然后取消任务:

task.cancel();

推荐阅读