java - 如何动态改变重复Java Runnable的周期?

标签 java runnable minecraft bukkit

首先,这是 Minecraft/Bukkit 相关的,但我相信我的问题不是 Bukkit 特有的,只是忽略了我认为(我希望)的一些小事情。

我的代码的最底部是一个randomDelayrandomPeriodrun() 函数根据这两个变量以给定的时间间隔重复运行。我不知道如何在可运行程序启动后动态更改这些。我想让可运行的每个周期的长度不同,但问题是,一旦 run() 函数开始,它似乎使用分配的第一个值。

package code.malon;

import java.util.Random;

import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitScheduler;

public final class RandomResponse extends JavaPlugin {

    Random rand = new Random();
    int min = 20;
    int max = 200;
    long randomDelay = rand.nextInt((max - min) + 1) + min;
    long randomPeriod = rand.nextInt((max - min) + 1) + min;

    public void onEnable() {

        BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
        scheduler.scheduleSyncRepeatingTask(this, new Runnable() {

            @Override
            public void run() {
                randomDelay = rand.nextInt((max - min) + 1) + min;
                randomPeriod = rand.nextInt((max - min) + 1) + min;
            }
        }, randomDelay, randomPeriod);
    }
}

最佳答案

让我们递归一下!噢耶!

您的代码不是动态的,因为您在 Bukkit 的 PluginClassLoader 构造 RandomResponse初始化字段。这将创建一个new Random(),生成一次随机值并安排其延迟“randomDelay”。那不是动态的。让我们用一个小技巧来解决这个问题:

public final class RandomResponse extends JavaPlugin {

    final Random rand = new Random();
    final int min = 20;
    final int max = 200;
    // I made these final for arbitrary reasons.

    private RandomResponse randomResponse;

    @Override
    public void onEnable() {
        randomResponse = this; // To use in anonymous class.

        // The delay should be random, so we compute it within onEnable() method.
        // We do not leave it in the class because then it's initialized by constructing.
        long randomDelay = rand.nextInt((max - min) + 1) + min;

        getServer().getScheduler().runTaskLater(this, new Runnable() {

            @Override
            public void run() {
                /*
                 * Stuff to do
                 */
                // Call itself again some time later.
                long randomDelay = rand.nextInt((max - min) + 1) + min;
                getServer().getScheduler().runTaskLater(randomResponse, this, randomDelay);
            }

        }, randomDelay);
    }
}

请注意,scheduleSyncRepeatingTask 在任务开始运行后无法更改其周期长度。因此,您必须递归调用。要允许取消并重新运行任务,请使用以下命令:

BukkitTask task;

void runTask() {
     cancelTask();
     task = getServer().getScheduler().runTaskLater(this, new Runnable() {

        @Override
        public void run() {
            /*
             * Stuff to do
             */
            // Call itself again some time later.
            long randomDelay = rand.nextInt((max - min) + 1) + min;
            task = getServer().getScheduler().runTaskLater(randomResponse, this, randomDelay);
        }

    }, randomDelay);
}

void cancelTask() {
    if (task != null) try {
        task.cancel();
    } catch(Throwable ex) {
        // Ignore.
    }
}

作为您可能没有想到的旁注,您可能需要使用 BukkitRunnable而不是 java.lang 中的 Runnable 类。

关于java - 如何动态改变重复Java Runnable的周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25837873/

相关文章:

java - 在循环中删除ArrayList中的元素

java - 在 Eclipse 中运行时加载资源时出现问题

java - 检查二维数组是否锯齿状

lua - 如何修复 "attempt to index a nil value"

java - 从任何字符串中获取最后三个字符 - Java

Android 向进度条或其他内容报告媒体播放器当前位置

java - 每次线程执行它的运行时获取一个值/返回一些东西

Java - 将方法传递给类并在新线程中执行

java - 如何阻止我的配置覆盖新值?

java - 使用 Forge 启动 Minecraft 1.12.2 时出现错误 : Could not find or load main class net. minecraft.launchwrapper.Launch