提供: Minecraft Modding Wiki
移動先: 案内検索

警告: ログインしていません。編集を行うと、あなたの IP アドレスが公開されます。ログインまたはアカウントを作成すれば、あなたの編集はその利用者名とともに表示されるほか、その他の利点もあります。

この編集を取り消せます。 下記の差分を確認して、本当に取り消していいか検証してください。よろしければ変更を保存して取り消しを完了してください。
最新版 編集中の文章
1行目: 1行目:
== スケジューラのプログラミング ==
+
== スケジューラチュートリアル  ==
 +
このチュートリアルでは、Bukkitのスケジューラの利用方法を説明しています。
  
このチュートリアルでは、bukkit によって提供されているスケジューラの使用方法をガイドします。<br>
+
== 主な注意事項  ==
スケジューラは、指定の時間後に実行される処理を書くことができます。<br>
 
これはリスナーやイベントへの応答で実行されるコードの記述方法とは異なります。<br>
 
また、繰り返しや、遅延の有無を設定したりすることもできます。この繰り返し処理は、処理が完了するか、キャンセルされるか、プラグインが無効になるまで実行できます。
 
  
スケジューラを利用した実装は、次のような手順を踏んでください。
+
主な注意事項は次の2点です。
# まず、スケジューラにより実行される処理内容を、[[#BukkitRunnable|BukkitRunnable]] を継承したクラスの run()メソッドで実装します。
+
* 他のスレッドからAPIのメソッドを(一部例外あり)を呼び出さない
# 次に、前のステップで実装したクラスをインスタンス化し、スケジュールをしたい箇所で、runTaskLaterメソッドやrunTaskTimerメソッドなどを実行するように設定します。
+
* メインのスレッドをスリープ状態にしてはならない
  
== BukkitRunnable ==
+
== Tutorial  ==
  
BukkitRunnableは、 抽象クラスRunnableの実装クラスです。<br>
+
The scheduler gives the following options;
Runnableに無い便利な機能として、自身の処理を再スケジュールしたり、キャンセルしたりできることです。
 
  
=== 処理の実装例 ===
+
Three types of task
  
スケジューラの処理を定義するには、まず BukkitRunnable を extends しましょう。
+
*Delayed Tasks
 +
*Repeating Tasks
 +
*Tasks which return a value
  
これはスケジュール処理のタスク定義の例です。
+
These tasks can be exeuted by two types of thread
<blockquote><source lang="java">
 
import org.bukkit.Bukkit;
 
import org.bukkit.scheduler.BukkitRunnable;
 
  
public class ExampleTask extends BukkitRunnable {
+
*Main server thread
 +
*Dedicated thread
  
    @Override
+
=== Thread Model<br>  ===
    public void run() {
+
 
        // スケジュールで実行する処理の内容をここに書きます。
+
The most important question when using the scheduler is deciding which thread types to use. Using the wrong thread type can cause intermittent problems that can be very hard to replicate. These problems may only occur on heavily used servers and not on a test server.
        Bukkit.broadcastMessage("サーバーへようこそ!説明文をちゃんと読んでね!");
+
 
    }
+
While the minecraft server is multi-threaded, there is one main server thread and other helper threads.
}
+
 
</source></blockquote>
+
Many data structures are only accessed by the server from the main thread. If you attempt to modify any of these from another thread, this may cause data corruption since two threads could be accessing the data at the same time.
 +
 
 +
The main thread handles the server clock tick system. It executes 20 times a second and then sleeps for the rest of the clock tick.
 +
 
 +
Very few Bukkit API calls are thread-safe. Unless you have checked that the API call you are making is thread-safe, it is best to assume that it isn't.
 +
 
 +
==== Synchronous Tasks<br>  ====
 +
 
 +
These are tasks that are executed by the main server thread.  
 +
 
 +
Remember: '''If this thread stops, the whole server will freeze.'''
 +
 
 +
<br> The main thread CAN be used for
 +
 
 +
*Scheduler method calls
 +
**Care needs to be taken when dealing with Future objects returned by the Scheduler (see below)  
 +
*Other tasks which don't block
 +
 
 +
<br> The main thread MUST be used for
 +
 
 +
*Tasks which call Bukkit API methods (except thread safe method, see below)
  
=== 実装した処理のスケジューリング ===
+
<br> The main thread MUST NOT be used for
  
タスクを定義した後、プラグインは、タスクをスケジュールする必要があります。<br>
+
*Tasks which put the current thread to sleep
BukkitRunnable は、指定の時間になったら、タスクのインスタンスが起動され、メソッドが実行されます。<br>
+
**This includes tasks which block, i.e. network read tasks
詳細は、BukkitRunnableのjavadoc を参照してください。<br>
 
これらのメソッドは共通して、BukkitTaskクラスのオブジェクトを返します。
 
  
これは、プレイヤーがログインしたら、20ticks(=1秒)後にタスクを実行するスケジューラを登録する実装例です。
+
<br> It is OK to use synchronize on the main thread, but only if you are sure that it will block for almost zero time.  
<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 {
+
==== Asynchronous Tasks<br>  ====
  
    @Override
+
These tasks are executed by a thread other than the main server thread. These threads can be put to sleep/blocked without causing any problems as the thread is dedicated to the task. The rules for these threads are the opposite of the rules for synchronous threads.  
    public void onEnable() {
 
        getServer().getPluginManager().registerEvents(this, this);
 
    }
 
  
    @EventHandler
+
<br> An async thread CAN be used for
    public void onJoin(PlayerJoinEvent event) {
 
        // BukkitRunnableを継承したExampleTaskを生成し、
 
        // runTaskLater メソッドで20ticks後に実行するように設定します。
 
        new ExampleTask().runTaskLater(this, 20);
 
    }
 
}
 
</source></blockquote>
 
  
== 自己キャンセルの実装例 ==
+
*Scheduler method calls
 +
*Other tasks which don't access the plugin API
  
今度は、プレイヤーがログインしたら、10ticks待った後、20ticksごとに5回実行し、その後スケジューラの処理をキャンセルする例を示します。
+
<br> An async thread MUST be used for
  
'''ExampleSelfCancelingTask.java'''
+
*Tasks which put the current thread to sleep
 +
**This includes tasks which block, i.e. network read tasks
  
<blockquote><source lang="java">
+
<br> An async thread MUST NOT be used for
import org.bukkit.plugin.java.JavaPlugin;
 
import org.bukkit.scheduler.BukkitRunnable;
 
  
public class ExampleSelfCancelingTask extends BukkitRunnable {
+
*Tasks which call Bukkit API methods (except thread safe method, see below)
  
    private final JavaPlugin plugin;
+
<br>
  
    private int counter;
+
== Task Types  ==
  
    public ExampleSelfCancelingTask(JavaPlugin plugin, int counter) {
+
There are 3 types of task, repeating tasks, delayed tasks, and tasks which return a value.  
        this.plugin = plugin;
 
        if (counter < 1) {
 
            throw new IllegalArgumentException("counter には1以上を指定してください。");
 
        } else {
 
            this.counter = counter;
 
        }
 
    }
 
  
    @Override
+
The API interface is described [[https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bukkit/scheduler/BukkitScheduler.java here]]
    public void run() {
 
        // ここに、スケジュールの処理内容を実装します。
 
        if (counter > 0) {
 
            plugin.getServer().broadcastMessage("広告が表示されるまで、あと " + counter-- + "秒");
 
        } else {
 
            plugin.getServer().broadcastMessage("サーバーへようこそ!説明文をちゃんと読んでね!");
 
            this.cancel();
 
        }
 
    }
 
}
 
</source></blockquote>
 
  
 +
==== Delayed Tasks  ====
  
'''ExamplePlugin.java'''
+
Tasks can be submitted to be executed after a delay. This delay can be set to zero.  
  
<blockquote><source lang="java">
+
====== Example  ======
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 {
+
This submits a task to the main thread to be executed after 3 seconds.
  
    @Override
+
myPlugin.getServer().getScheduler().scheduleSyncDelayedTask(myPlugin, new Runnable() {
     public void onEnable() {
+
         getServer().getPluginManager().registerEvents(this, this);
+
     public void run() {
 +
         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.
 +
 +
This code could be executed by another thread. If the code
 +
 +
getServer().broadcastMessage("This message is broadcast by an async thread");
  
    @EventHandler
+
was executed by another thread, it could cause problems since the broadcastMessage method is being executed by another thread.  
    public void onJoin(PlayerJoinEvent event) {
 
        // スケジューリングする
 
        new ExampleSelfCancelingTask(this, 5).runTaskTimer(this, 10, 20);
 
    }
 
}
 
</source></blockquote>
 
  
== 無名クラスを使用した実装例 ==
+
==== Repeating Tasks  ====
  
毎回BukkitRunnableを継承したクラスを作成していると大変なので、BukkitRunnableを無名クラスとして内部に実装した例も示します。<br>
+
Tasks can be submitted to be repeated. An initial delay is also set.
無名クラスを理解している場合は、こちらを使っても構いません。
 
  
<blockquote><source lang="java">
+
====== Example  ======
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 {
+
This submits a task to an async thread to be executed after 3 seconds with a period of 10 seconds.
  
    @Override
+
myPlugin.getServer().getScheduler().scheduleAsyncRepeatingTask(myPlugin, new Runnable() {
     public void onEnable() {
+
         getServer().getPluginManager().registerEvents(this, this);
+
     public void run() {
 +
         System.out.println("This message is printed by an async thread");
 
     }
 
     }
 +
}, 60L, 200L);
  
    @EventHandler
+
Both times count in server ticks. The initial delay is 60/20 = 3 seconds and the period is 200/20 = 10 seconds.
    public void onJoin(PlayerJoinEvent event) {
 
        // 20ticks後に1度だけ実行される処理を、実装しつつ、そのままスケジュールします。
 
       
 
        new BukkitRunnable() {
 
  
            @Override
+
The above code will print "This message is printed by an async thread" every 10 seconds.  
            public void run() {
 
                // スケジューラで実行される処理内容を、ここに実装します。
 
                getServer().broadcastMessage(
 
                    "サーバーへようこそ!説明文をちゃんと読んでね!");
 
            }
 
        }.runTaskLater(this, 20);
 
        // ↑そのままスケジュールします。
 
    }
 
}
 
</source></blockquote>
 
  
== BukkitScheduler ==
+
==== Tasks which return a value  ====
  
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>
+
It is possible to submit tasks which return a value to the scheduler. Only submission for execution by the main thread is supported.  
詳細は、[http://jd.bukkit.org/rb/apidocs/index.html?org/bukkit/scheduler/BukkitScheduler.html BukkitSchedulerのjavadoc] を参照してください。<br>
 
なお、BukkitSchedulerのメソッドで実行できる内容は、BukkitRunnableのメソッドで実行できる内容と全く同じです。
 
  
{{warning}} ただし、BukkitSchedulerでBukkitRunnableを実行することも可能ですが、BukkitRunnableのcancel()メソッドを使ってスケジューラをキャンセルすることができないことに注意してください。<br>
+
The purpose of this system is to allow API methods that return values to be called by other threads.  
{{warning}} この実装方法は、CraftBukkit 1.7.10-R0.1 で非推奨に設定されました。今後は前述のBukkitRunnableのメソッドを呼び出す方法を使用してください。
 
  
=== 実装例1 ===
+
The scheduler returns a Future object that can be used to obtain the result.
  
無名クラスでRunnableを実装し、20ticks後に実行される例を示します。
+
====== Example  ======
<blockquote><source lang="java">
 
import org.bukkit.Bukkit;
 
import org.bukkit.plugin.java.JavaPlugin;
 
import org.bukkit.scheduler.BukkitScheduler;
 
  
public final class ExamplePlugin extends JavaPlugin {
+
Future&lt;String&gt; returnFuture = myPlugin.getServer().getScheduler().callSyncMethod(myPlugin, new Callable&lt;String&gt;() {
    public void onEnable() {
+
        BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
+
    public String call() {
        scheduler.scheduleSyncDelayedTask(this, new Runnable() {
+
         return "This is the string to return";
            @Override
 
            public void run() {
 
                // ここに処理を実装する。
 
            }
 
         }, 20L);
 
 
     }
 
     }
}
+
</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();
 +
}
 +
   
  
=== 実行例2 ===
+
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.
  
無名クラスでRunnableを実装し、20ticksごとにプラグインが終了するまでずっと実行され続ける例を示します。
+
====== Use From The Main Thread  ======
<blockquote><source lang="java">
 
import org.bukkit.Bukkit;
 
import org.bukkit.plugin.java.JavaPlugin;
 
import org.bukkit.scheduler.BukkitScheduler;
 
  
public final class ExamplePlugin extends JavaPlugin {
+
This is '''NOT''' recommended.
    public void onEnable() {
+
 
        BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
+
This system isn't intended to be used from the main thread.  
        scheduler.scheduleSyncRepeatingTask(this, new Runnable() {
 
            @Override
 
            public void run() {
 
                // ここに処理を実装する。
 
            }
 
        }, 0L, 20L);
 
    }
 
}
 
</source></blockquote>
 
  
=== BukkitTask ===
+
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クラスのオブジェクトは、Runnableがスケジュールされたときに返されます。<br>
+
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).  
このオブジェクトは、スケジューラにより実行されるスケジュールタスクを表現しています。<br>
 
詳細は、[http://jd.bukkit.org/rb/apidocs/index.html?org/bukkit/scheduler/BukkitTask.html BukkitTaskのjavadoc] を参照してください。
 
  
=== Callable と Future ===
+
== Thread Safe API Methods ==
  
Callableクラスは、同期処理を呼び出したときに、[http://docs.oracle.com/javase/1.5.0/docs/api/index.html?java/util/concurrent/Future.html Future]クラスのオブジェクトを返します。<br>
+
Bukkit API methods which are thread safe are:  
これは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.
  
1. 非同期実行タスクは、BukkitのAPIを直接実行してはいけません。<br>
+
{{Languages|Scheduler_Programming}}
2. 非同期タスクのコレクションにアクセスしたり、内容を変更しないでください。通常のコレクションはスレッドセーフではありません。<br>
+
[[Category:Tutorials]]
3. 非同期タスクは、同期タスクをスケジュールすることができます。<br>
 
4. 同期タスクは、非同期タスクをスケジュールすることができます。
 

Minecraft Modding Wikiへの投稿はすべて、他の投稿者によって編集、変更、除去される場合があります。 自分が書いたものが他の人に容赦なく編集されるのを望まない場合は、ここに投稿しないでください。
また、投稿するのは、自分で書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください(詳細はMinecraft Modding Wiki:著作権を参照)。 著作権保護されている作品は、許諾なしに投稿しないでください!

このページを編集するには、下記の確認用の質問に回答してください (詳細):

取り消し 編集の仕方 (新しいウィンドウで開きます)

このページで使用されているテンプレート: