提供: Minecraft Modding Wiki
移動先: 案内検索
(Asynchronous Tasks)
(BukkitSchedulerがDepricatedされたことによる注意の追記。)
 
(3人の利用者による、間の40版が非表示)
1行目: 1行目:
== スケジューラチュートリアル  ==
+
== スケジューラのプログラミング ==
このチュートリアルでは、Bukkitのスケジューラの利用方法を説明しています。
 
  
== 主な注意事項  ==
+
このチュートリアルでは、bukkit によって提供されているスケジューラの使用方法をガイドします。<br>
 +
スケジューラは、指定の時間後に実行される処理を書くことができます。<br>
 +
これはリスナーやイベントへの応答で実行されるコードの記述方法とは異なります。<br>
 +
また、繰り返しや、遅延の有無を設定したりすることもできます。この繰り返し処理は、処理が完了するか、キャンセルされるか、プラグインが無効になるまで実行できます。
  
主な注意事項は次の2点です。
+
スケジューラを利用した実装は、次のような手順を踏んでください。
* 他のスレッドからAPIのメソッドを(一部例外あり)を呼び出さない
+
# まず、スケジューラにより実行される処理内容を、[[#BukkitRunnable|BukkitRunnable]] を継承したクラスの run()メソッドで実装します。
* メインのスレッドをスリープ状態にしてはならない
+
# 次に、前のステップで実装したクラスをインスタンス化し、スケジュールをしたい箇所で、runTaskLaterメソッドやrunTaskTimerメソッドなどを実行するように設定します。
  
== Tutorial  ==
+
== BukkitRunnable ==
  
スケジューラは次の3種類のタスクをオプションとして提供しています。
+
BukkitRunnableは、 抽象クラスRunnableの実装クラスです。<br>
*遅延タスク(Delayed Task)
+
Runnableに無い便利な機能として、自身の処理を再スケジュールしたり、キャンセルしたりできることです。
*連続タスク(Repeating Task)
 
*戻り値を返すタスク
 
  
これらのタスクは2種類のスレッドとして実行する事ができます。
+
=== 処理の実装例 ===
*メインサーバスレッド
 
*専用スレッド
 
  
=== Thread Model<br>  ===
+
スケジューラの処理を定義するには、まず BukkitRunnable を extends しましょう。
  
スケジューラにどのスレッドタイプを利用すれば良いかが、最も重要な問題です。
+
これはスケジュール処理のタスク定義の例です。
間違ったスレッドタイプを利用すると、検出が困難な障害を断続的に発生させる原因となります。また、そのような障害は試験サーバでは発生せず、頻繁に連続稼動しているサーバでのみ発生する場合がある等、再現性が低い障害である場合もあるため、原因の特定を更に困難にします。
+
<blockquote><source lang="java">
 +
import org.bukkit.Bukkit;
 +
import org.bukkit.scheduler.BukkitRunnable;
  
Minecraftサーバはマルチスレッドであり、一つのメインサーバーのスレッドと他のヘルパースレッドが存在します。
+
public class ExampleTask extends BukkitRunnable {
  
多くのデータ構造は、サーバのメインスレッドからのみアクセスされます。別のスレッドからこれらのデータを変更しようとすると、2つのスレッドが同時にデータにアクセスする事になるため、データ破損を引き起こす可能性があります。
+
    @Override
 +
    public void run() {
 +
        // スケジュールで実行する処理の内容をここに書きます。
 +
        Bukkit.broadcastMessage("サーバーへようこそ!説明文をちゃんと読んでね!");
 +
    }
 +
}
 +
</source></blockquote>
  
メインスレッドは、サーバーのClock-Tickを処理します。他タスクこのスレッドは、他のClock-Tickを実行可能とするために、秒間20回のスリープを実行します。
+
=== 実装した処理のスケジューリング ===
  
少数のBukkitAPIはスレッドセーフです。あなたのプラグインが使っているAPIがスレッドセーフなものである事を確認していない限り、基本的にBukkitAPIの命令はスレッドセーフではないものとして開発して下さい
+
タスクを定義した後、プラグインは、タスクをスケジュールする必要があります。<br>
 +
BukkitRunnable は、指定の時間になったら、タスクのインスタンスが起動され、メソッドが実行されます。<br>
 +
詳細は、BukkitRunnableのjavadoc を参照してください。<br>
 +
これらのメソッドは共通して、BukkitTaskクラスのオブジェクトを返します。
  
==== 同期タスク ====
+
これは、プレイヤーがログインしたら、20ticks(=1秒)後にタスクを実行するスケジューラを登録する実装例です。
サーバのメインスレッドが実行するタスクです。
+
<blockquote><source lang="java">
 +
import org.bukkit.event.EventHandler;
 +
import org.bukkit.event.Listener;
 +
import org.bukkit.event.player.PlayerJoinEvent;
 +
import org.bukkit.plugin.java.JavaPlugin;
  
:'''重要''': '''このスレッドが停止すると、サーバがフリーズします。'''
+
public class ExamplePlugin extends JavaPlugin implements Listener {
  
<br> メインスレッドは下記の用途に'''使えます'''
+
    @Override
* スケジューラメソッドの呼び出し
+
    public void onEnable() {
** 将来、スケジューラの戻り値の仕様が変更される可能性があるため注意して下さい(下記参照)
+
        getServer().getPluginManager().registerEvents(this, this);
*停止・待機処理を行わないタスク
+
    }
  
<br> メインスレッドは下記の用途に'''使わなくてはいけません'''
+
    @EventHandler
*Bukkit APIのメソッドを呼び出すタスク(スレッドセーフな方法を除いては、下記参照)
+
    public void onJoin(PlayerJoinEvent event) {
 +
        // BukkitRunnableを継承したExampleTaskを生成し、
 +
        // runTaskLater メソッドで20ticks後に実行するように設定します。
 +
        new ExampleTask().runTaskLater(this, 20);
 +
    }
 +
}
 +
</source></blockquote>
  
<br> メインスレッドは下記の用途に'''使ってはいけません'''
+
== 自己キャンセルの実装例 ==
*自スレッドをスリープ状態にするタスク
 
**停止・待機処理を含むスレッド。(例:ネットワーク通信の受信タスク)
 
  
 +
今度は、プレイヤーがログインしたら、10ticks待った後、20ticksごとに5回実行し、その後スケジューラの処理をキャンセルする例を示します。
  
メインスレッド上で同期タスクを実行する事自体は良いのですが、待機や停止の時間がほぼゼロであるものに限ります。(訳者注:1つの処理ステップが長時間を費やす処理は、サーバ自体をその間待機状態に置いてしまうため、メインスレッド上で行うべきではない事を説明しています。)
+
'''ExampleSelfCancelingTask.java'''
  
==== 非同期タスク ====
+
<blockquote><source lang="java">
 +
import org.bukkit.plugin.java.JavaPlugin;
 +
import org.bukkit.scheduler.BukkitRunnable;
  
非同期タスクは、サーバのメインスレッド以外のスレッドによって実行されます。専用のタスクとして実行されるため、同期タスクで説明したような問題を引き起こすことなく、自タスクを停止・スリープ状態にする事ができます。この特性は、同期タスクの真逆に相当します。
+
public class ExampleSelfCancelingTask extends BukkitRunnable {
  
<br> 非同期タスクは下記の用途に'''利用できます'''
+
    private final JavaPlugin plugin;
  
*スケジューラメソッドの呼び出し
+
    private int counter;
*プラグインAPIを利用しないタスク
 
  
<br> 非同期タスクは下記の用途に'''利用しなければなりません'''
+
    public ExampleSelfCancelingTask(JavaPlugin plugin, int counter) {
 +
        this.plugin = plugin;
 +
        if (counter < 1) {
 +
            throw new IllegalArgumentException("counter には1以上を指定してください。");
 +
        } else {
 +
            this.counter = counter;
 +
        }
 +
    }
  
*自スレッドをスリープ状態にするタスク
+
    @Override
**This includes tasks which block, i.e. network read tasks
+
    public void run() {
 +
        // ここに、スケジュールの処理内容を実装します。
 +
        if (counter > 0) {
 +
            plugin.getServer().broadcastMessage("広告が表示されるまで、あと " + counter-- + "秒");
 +
        } else {
 +
            plugin.getServer().broadcastMessage("サーバーへようこそ!説明文をちゃんと読んでね!");
 +
            this.cancel();
 +
        }
 +
    }
 +
}
 +
</source></blockquote>
  
<br> 非同期タスクは下記の用途に'''利用してはいけません'''
 
  
*Tasks which call Bukkit API methods (except thread safe method, see below)
+
'''ExamplePlugin.java'''
  
<br>
+
<blockquote><source lang="java">
 +
import org.bukkit.event.EventHandler;
 +
import org.bukkit.event.Listener;
 +
import org.bukkit.event.player.PlayerJoinEvent;
 +
import org.bukkit.plugin.java.JavaPlugin;
  
== Task Types  ==
+
public final class ExamplePlugin extends JavaPlugin implements Listener {
  
There are 3 types of task, repeating tasks, delayed tasks, and tasks which return a value.
+
    @Override
 +
    public void onEnable() {
 +
        getServer().getPluginManager().registerEvents(this, this);
 +
    }
  
The API interface is described [[https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bukkit/scheduler/BukkitScheduler.java here]]
+
    @EventHandler
 +
    public void onJoin(PlayerJoinEvent event) {
 +
        // スケジューリングする
 +
        new ExampleSelfCancelingTask(this, 5).runTaskTimer(this, 10, 20);
 +
    }
 +
}
 +
</source></blockquote>
  
==== Delayed Tasks  ====
+
== 無名クラスを使用した実装例 ==
  
Tasks can be submitted to be executed after a delay. This delay can be set to zero.
+
毎回BukkitRunnableを継承したクラスを作成していると大変なので、BukkitRunnableを無名クラスとして内部に実装した例も示します。<br>
 +
無名クラスを理解している場合は、こちらを使っても構いません。
  
====== Example  ======
+
<blockquote><source lang="java">
 +
import org.bukkit.event.EventHandler;
 +
import org.bukkit.event.Listener;
 +
import org.bukkit.event.player.PlayerJoinEvent;
 +
import org.bukkit.plugin.java.JavaPlugin;
 +
import org.bukkit.scheduler.BukkitRunnable;
  
This submits a task to the main thread to be executed after 3 seconds.
+
public final class ExamplePlugin extends JavaPlugin implements Listener {
  
myPlugin.getServer().getScheduler().scheduleSyncDelayedTask(myPlugin, new Runnable() {
+
    @Override
+
     public void onEnable() {
     public void run() {
+
         getServer().getPluginManager().registerEvents(this, this);
         getServer().broadcastMessage("This message is broadcast by the main thread");
 
 
     }
 
     }
}, 60L);
 
  
The time delay is 60. This counts in server ticks. There are 20 ticks per second, so the delay is 60/20 = 3.
+
    @EventHandler
 +
    public void onJoin(PlayerJoinEvent event) {
 +
        // 20ticks後に1度だけ実行される処理を、実装しつつ、そのままスケジュールします。
 +
       
 +
        new BukkitRunnable() {
  
This code could be executed by another thread. If the code
+
            @Override
 
+
            public void run() {
getServer().broadcastMessage("This message is broadcast by an async thread");
+
                // スケジューラで実行される処理内容を、ここに実装します。
 +
                getServer().broadcastMessage(
 +
                    "サーバーへようこそ!説明文をちゃんと読んでね!");
 +
            }
 +
        }.runTaskLater(this, 20);
 +
        // ↑そのままスケジュールします。
 +
    }
 +
}
 +
</source></blockquote>
  
was executed by another thread, it could cause problems since the broadcastMessage method is being executed by another thread.
+
== BukkitScheduler ==
  
==== Repeating Tasks  ====
+
BukkitSchedulerは、[http://docs.oracle.com/javase/1.5.0/docs/api/index.html?java/lang/Runnable.html Runnable]クラスや[http://docs.oracle.com/javase/1.5.0/docs/api/index.html?java/util/concurrent/Callable.html Callable]クラスの、どちらかまたは両方を実装したクラスを、一定時間後に実行する機能を提供します。<br>
 +
詳細は、[http://jd.bukkit.org/rb/apidocs/index.html?org/bukkit/scheduler/BukkitScheduler.html BukkitSchedulerのjavadoc] を参照してください。<br>
 +
なお、BukkitSchedulerのメソッドで実行できる内容は、BukkitRunnableのメソッドで実行できる内容と全く同じです。
  
Tasks can be submitted to be repeated. An initial delay is also set.  
+
{{warning}} ただし、BukkitSchedulerでBukkitRunnableを実行することも可能ですが、BukkitRunnableのcancel()メソッドを使ってスケジューラをキャンセルすることができないことに注意してください。<br>
 +
{{warning}} この実装方法は、CraftBukkit 1.7.10-R0.1 で非推奨に設定されました。今後は前述のBukkitRunnableのメソッドを呼び出す方法を使用してください。
  
====== Example  ======
+
=== 実装例1 ===
  
This submits a task to an async thread to be executed after 3 seconds with a period of 10 seconds.  
+
無名クラスでRunnableを実装し、20ticks後に実行される例を示します。
 +
<blockquote><source lang="java">
 +
import org.bukkit.Bukkit;
 +
import org.bukkit.plugin.java.JavaPlugin;
 +
import org.bukkit.scheduler.BukkitScheduler;
  
myPlugin.getServer().getScheduler().scheduleAsyncRepeatingTask(myPlugin, new Runnable() {
+
public final class ExamplePlugin extends JavaPlugin {
+
    public void onEnable() {
    public void run() {
+
        BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
         System.out.println("This message is printed by an async thread");
+
        scheduler.scheduleSyncDelayedTask(this, new Runnable() {
 +
            @Override
 +
            public void run() {
 +
                // ここに処理を実装する。
 +
            }
 +
         }, 20L);
 
     }
 
     }
}, 60L, 200L);
+
}
 
+
</source></blockquote>
Both times count in server ticks. The initial delay is 60/20 = 3 seconds and the period is 200/20 = 10 seconds.
 
 
 
The above code will print "This message is printed by an async thread" every 10 seconds.
 
  
==== Tasks which return a value  ====
+
=== 実行例2 ===
  
It is possible to submit tasks which return a value to the scheduler. Only submission for execution by the main thread is supported.
+
無名クラスでRunnableを実装し、20ticksごとにプラグインが終了するまでずっと実行され続ける例を示します。
 +
<blockquote><source lang="java">
 +
import org.bukkit.Bukkit;
 +
import org.bukkit.plugin.java.JavaPlugin;
 +
import org.bukkit.scheduler.BukkitScheduler;
  
The purpose of this system is to allow API methods that return values to be called by other threads.
+
public final class ExamplePlugin extends JavaPlugin {
 
+
    public void onEnable() {
The scheduler returns a Future object that can be used to obtain the result.
+
        BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
 
+
        scheduler.scheduleSyncRepeatingTask(this, new Runnable() {
====== Example  ======
+
            @Override
 
+
            public void run() {
Future&lt;String&gt; returnFuture = myPlugin.getServer().getScheduler().callSyncMethod(myPlugin, new Callable&lt;String&gt;() {
+
                // ここに処理を実装する。
+
            }
    public String call() {
+
         }, 0L, 20L);
         return "This is the string to return";
 
 
     }
 
     }
+
}
});
+
</source></blockquote>
 
try {
 
    // This will block the current thread
 
    String returnValue = returnFuture.get();
 
    System.out.println(returnValue);
 
} catch (InterruptedException e) {
 
    System.out.println("Interrupt triggered which waiting on callable to return");
 
} catch (ExecutionException e) {
 
    System.out.println("Callable task threw an exception");
 
    ee.getCause().printStackTrace();
 
}
 
   
 
 
 
This will submit the callable and then use the Future.get() method. This method sleeps the current thread until the Callable has returned a value and gets the result.
 
 
 
====== Use From The Main Thread  ======
 
 
 
This is '''NOT''' recommended.
 
 
 
This system isn't intended to be used from the main thread.
 
  
If you use the .get() method on the future, it sleeps the current thread (i.e. the main thread), until the (asleep) main thread completes the task.
+
=== BukkitTask ===
  
If you absolutely must use it in the main thread, you MUST check the .isDone() method before calling the .get() method of Future objects returned by the scheduler. Otherwise, the main thread will sleep waiting for the task to be completed (by the main thread).
+
BukkitTaskクラスのオブジェクトは、Runnableがスケジュールされたときに返されます。<br>
 +
このオブジェクトは、スケジューラにより実行されるスケジュールタスクを表現しています。<br>
 +
詳細は、[http://jd.bukkit.org/rb/apidocs/index.html?org/bukkit/scheduler/BukkitTask.html BukkitTaskのjavadoc] を参照してください。
  
== Thread Safe API Methods ==
+
=== Callable と Future ===
  
Bukkit API methods which are thread safe are:  
+
Callableクラスは、同期処理を呼び出したときに、[http://docs.oracle.com/javase/1.5.0/docs/api/index.html?java/util/concurrent/Future.html Future]クラスのオブジェクトを返します。<br>
 +
これはJavaで提供されている機能やクラスです。<br>
 +
詳細は、[http://docs.oracle.com/javase/1.5.0/docs/api/index.html?java/util/concurrent/Callable.html Callableのjavadoc] や、[http://docs.oracle.com/javase/1.5.0/docs/api/index.html?java/util/concurrent/Future.html Futureのjavadoc] を参照してください。
  
*All the scheduler methods
+
== スレッドの安全性のためのヒント ==
*[http://jd.bukkit.org/apidocs/org/bukkit/Bukkit.html#getServer() Bukkit.getServer()]
 
*[http://jd.bukkit.org/apidocs/org/bukkit/Server.html#getBukkitVersion() Server.getBukkitVersion()]
 
*[http://jd.bukkit.org/apidocs/org/bukkit/World.html#getUID() World.getUID()]
 
*[http://jd.bukkit.org/apidocs/org/bukkit/World.html#getMaxHeight() World.getMaxHeight()]
 
*[http://jd.bukkit.org/apidocs/org/bukkit/World.html#getSeed() World.getSeed()]
 
*[http://jd.bukkit.org/apidocs/src-html/org/bukkit/World.html#line.51 World.getBlockTypeIdAt(int x, int y, int z)]
 
*[http://jd.bukkit.org/apidocs/org/bukkit/entity/Entity.html#getEntityId() Entity.getEntityId()]
 
*[http://jd.bukkit.org/apidocs/org/bukkit/entity/Entity.html#getUniqueId() Entity.getUniqueId()]
 
**This list is not complete.
 
  
{{Languages|Scheduler_Programming}}
+
1. 非同期実行タスクは、BukkitのAPIを直接実行してはいけません。<br>
[[Category:Tutorials]]
+
2. 非同期タスクのコレクションにアクセスしたり、内容を変更しないでください。通常のコレクションはスレッドセーフではありません。<br>
 +
3. 非同期タスクは、同期タスクをスケジュールすることができます。<br>
 +
4. 同期タスクは、非同期タスクをスケジュールすることができます。

2014年8月12日 (火) 23:00時点における最新版

スケジューラのプログラミング[編集]

このチュートリアルでは、bukkit によって提供されているスケジューラの使用方法をガイドします。
スケジューラは、指定の時間後に実行される処理を書くことができます。
これはリスナーやイベントへの応答で実行されるコードの記述方法とは異なります。
また、繰り返しや、遅延の有無を設定したりすることもできます。この繰り返し処理は、処理が完了するか、キャンセルされるか、プラグインが無効になるまで実行できます。

スケジューラを利用した実装は、次のような手順を踏んでください。

  1. まず、スケジューラにより実行される処理内容を、BukkitRunnable を継承したクラスの run()メソッドで実装します。
  2. 次に、前のステップで実装したクラスをインスタンス化し、スケジュールをしたい箇所で、runTaskLaterメソッドやrunTaskTimerメソッドなどを実行するように設定します。

BukkitRunnable[編集]

BukkitRunnableは、 抽象クラスRunnableの実装クラスです。
Runnableに無い便利な機能として、自身の処理を再スケジュールしたり、キャンセルしたりできることです。

処理の実装例[編集]

スケジューラの処理を定義するには、まず BukkitRunnable を extends しましょう。

これはスケジュール処理のタスク定義の例です。

import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitRunnable;

public class ExampleTask extends BukkitRunnable {

    @Override
    public void run() {
        // スケジュールで実行する処理の内容をここに書きます。
        Bukkit.broadcastMessage("サーバーへようこそ!説明文をちゃんと読んでね!");
    }
}

実装した処理のスケジューリング[編集]

タスクを定義した後、プラグインは、タスクをスケジュールする必要があります。
BukkitRunnable は、指定の時間になったら、タスクのインスタンスが起動され、メソッドが実行されます。
詳細は、BukkitRunnableのjavadoc を参照してください。
これらのメソッドは共通して、BukkitTaskクラスのオブジェクトを返します。

これは、プレイヤーがログインしたら、20ticks(=1秒)後にタスクを実行するスケジューラを登録する実装例です。

import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;

public class ExamplePlugin extends JavaPlugin implements Listener {

    @Override
    public void onEnable() {
        getServer().getPluginManager().registerEvents(this, this);
    }

    @EventHandler
    public void onJoin(PlayerJoinEvent event) {
        // BukkitRunnableを継承したExampleTaskを生成し、
        // runTaskLater メソッドで20ticks後に実行するように設定します。
        new ExampleTask().runTaskLater(this, 20);
    }
}

自己キャンセルの実装例[編集]

今度は、プレイヤーがログインしたら、10ticks待った後、20ticksごとに5回実行し、その後スケジューラの処理をキャンセルする例を示します。

ExampleSelfCancelingTask.java

import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;

public class ExampleSelfCancelingTask extends BukkitRunnable {

    private final JavaPlugin plugin;

    private int counter;

    public ExampleSelfCancelingTask(JavaPlugin plugin, int counter) {
        this.plugin = plugin;
        if (counter < 1) {
            throw new IllegalArgumentException("counter には1以上を指定してください。");
        } else {
            this.counter = counter;
        }
    }

    @Override
    public void run() {
        // ここに、スケジュールの処理内容を実装します。
        if (counter > 0) {
            plugin.getServer().broadcastMessage("広告が表示されるまで、あと " + counter-- + "秒");
        } else {
            plugin.getServer().broadcastMessage("サーバーへようこそ!説明文をちゃんと読んでね!");
            this.cancel();
        }
    }
}


ExamplePlugin.java

import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;

public final class ExamplePlugin extends JavaPlugin implements Listener {

    @Override
    public void onEnable() {
        getServer().getPluginManager().registerEvents(this, this);
    }

    @EventHandler
    public void onJoin(PlayerJoinEvent event) {
        // スケジューリングする
        new ExampleSelfCancelingTask(this, 5).runTaskTimer(this, 10, 20);
    }
}

無名クラスを使用した実装例[編集]

毎回BukkitRunnableを継承したクラスを作成していると大変なので、BukkitRunnableを無名クラスとして内部に実装した例も示します。
無名クラスを理解している場合は、こちらを使っても構いません。

import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;

public final class ExamplePlugin extends JavaPlugin implements Listener {

    @Override
    public void onEnable() {
        getServer().getPluginManager().registerEvents(this, this);
    }

    @EventHandler
    public void onJoin(PlayerJoinEvent event) {
        // 20ticks後に1度だけ実行される処理を、実装しつつ、そのままスケジュールします。
        
        new BukkitRunnable() {

            @Override
            public void run() {
                // スケジューラで実行される処理内容を、ここに実装します。
                getServer().broadcastMessage(
                    "サーバーへようこそ!説明文をちゃんと読んでね!");
            }
        }.runTaskLater(this, 20);
        // ↑そのままスケジュールします。
    }
}

BukkitScheduler[編集]

BukkitSchedulerは、RunnableクラスやCallableクラスの、どちらかまたは両方を実装したクラスを、一定時間後に実行する機能を提供します。
詳細は、BukkitSchedulerのjavadoc を参照してください。
なお、BukkitSchedulerのメソッドで実行できる内容は、BukkitRunnableのメソッドで実行できる内容と全く同じです。

Attention.pngWarning: ただし、BukkitSchedulerでBukkitRunnableを実行することも可能ですが、BukkitRunnableのcancel()メソッドを使ってスケジューラをキャンセルすることができないことに注意してください。
Attention.pngWarning: この実装方法は、CraftBukkit 1.7.10-R0.1 で非推奨に設定されました。今後は前述のBukkitRunnableのメソッドを呼び出す方法を使用してください。

実装例1[編集]

無名クラスでRunnableを実装し、20ticks後に実行される例を示します。

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

public final class ExamplePlugin extends JavaPlugin {
    public void onEnable() {
        BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
        scheduler.scheduleSyncDelayedTask(this, new Runnable() {
            @Override
            public void run() {
                // ここに処理を実装する。
            }
        }, 20L);
    }
}

実行例2[編集]

無名クラスでRunnableを実装し、20ticksごとにプラグインが終了するまでずっと実行され続ける例を示します。

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

public final class ExamplePlugin extends JavaPlugin {
    public void onEnable() {
        BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
        scheduler.scheduleSyncRepeatingTask(this, new Runnable() {
            @Override
            public void run() {
                // ここに処理を実装する。
            }
        }, 0L, 20L);
    }
}

BukkitTask[編集]

BukkitTaskクラスのオブジェクトは、Runnableがスケジュールされたときに返されます。
このオブジェクトは、スケジューラにより実行されるスケジュールタスクを表現しています。
詳細は、BukkitTaskのjavadoc を参照してください。

Callable と Future[編集]

Callableクラスは、同期処理を呼び出したときに、Futureクラスのオブジェクトを返します。
これはJavaで提供されている機能やクラスです。
詳細は、Callableのjavadoc や、Futureのjavadoc を参照してください。

スレッドの安全性のためのヒント[編集]

1. 非同期実行タスクは、BukkitのAPIを直接実行してはいけません。
2. 非同期タスクのコレクションにアクセスしたり、内容を変更しないでください。通常のコレクションはスレッドセーフではありません。
3. 非同期タスクは、同期タスクをスケジュールすることができます。
4. 同期タスクは、非同期タスクをスケジュールすることができます。