細 (→Task Types) |
細 (→タスクの種類) |
||
73行目: | 73行目: | ||
== タスクの種類 == | == タスクの種類 == | ||
− | + | タスクには、連続タスク, 遅延タスク, 戻り値を返すタスク, の3種類があります。 | |
− | + | APIのインタフェースの仕様については[[https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bukkit/scheduler/BukkitScheduler.java こちら]]を参照して下さい。 | |
− | |||
− | |||
==== 遅延タスク ==== | ==== 遅延タスク ==== | ||
− | + | 一定の遅延を置いてから実行されるタスクです。遅延時間にはゼロを指定可能です。 | |
====== 具体例 ====== | ====== 具体例 ====== | ||
101行目: | 99行目: | ||
was executed by another thread, it could cause problems since the broadcastMessage method is being executed by another thread. | was executed by another thread, it could cause problems since the broadcastMessage method is being executed by another thread. | ||
− | ==== | + | ==== 繰り返しタスク ==== |
− | + | 繰り返し実行されるタスクです。遅延時間も設定可能です。 | |
====== 具体例 ====== | ====== 具体例 ====== | ||
122行目: | 120行目: | ||
==== 戻り値を返すタスク ==== | ==== 戻り値を返すタスク ==== | ||
− | + | スケジューラから戻り値を返す事ができるタスクです。メインスレッドから実行可能なタスクです。 | |
− | + | この仕組みの目的は、他タスクから呼ばれたAPIのメソッドに戻り値を返させる事です。 | |
− | + | スケジューラは、戻り値として返されるであろうオブジェクトを取得可能にします。 | |
====== 具体例 ====== | ====== 具体例 ====== |
2012年6月24日 (日) 03:02時点における版
目次
スケジューラの解説
この解説では、Bukkitのスケジューラの利用方法を説明しています。
主な注意事項
主な注意事項は次の2点です。
- 他のスレッドからAPIのメソッドを(一部例外あり)を呼び出さない
- メインのスレッドをスリープ状態にしてはならない
解説
スケジューラは次の3種類のタスクをオプションとして提供しています。
- 遅延タスク(Delayed Task)
- 連続タスク(Repeating Task)
- 戻り値を返すタスク
これらのタスクは2種類のスレッドとして実行する事ができます。
- メインサーバスレッド
- 専用スレッド
スレッドの種類
スケジューラにどのスレッドタイプを利用すれば良いかが、最も重要な問題です。 間違ったスレッドタイプを利用すると、検出が困難な障害を断続的に発生させる原因となります。また、そのような障害は試験サーバでは発生せず、頻繁に連続稼動しているサーバでのみ発生する場合がある等、再現性が低い障害である場合もあるため、原因の特定を更に困難にします。
Minecraftサーバはマルチスレッドであり、一つのメインサーバーのスレッドと他のヘルパースレッドが存在します。
多くのデータ構造は、サーバのメインスレッドからのみアクセスされます。別のスレッドからこれらのデータを変更しようとすると、2つのスレッドが同時にデータにアクセスする事になるため、データ破損を引き起こす可能性があります。
メインスレッドは、サーバーのClock-Tickを処理します。他タスクこのスレッドは、他のClock-Tickを実行可能とするために、秒間20回のスリープを実行します。
少数のBukkitAPIはスレッドセーフです。あなたのプラグインが使っているAPIがスレッドセーフなものである事を確認していない限り、基本的にBukkitAPIの命令はスレッドセーフではないものとして開発して下さい
同期タスク
サーバのメインスレッドが実行するタスクです。
- 重要: このスレッドが停止すると、サーバがフリーズします。
メインスレッドは下記の用途に使えます
- スケジューラメソッドの呼び出し
- 将来、スケジューラの戻り値の仕様が変更される可能性があるため注意して下さい(下記参照)
- 停止・待機処理を行わないタスク
メインスレッドは下記の用途に使わなくてはいけません
- Bukkit APIのメソッドを呼び出すタスク(スレッドセーフな方法を除いては、下記参照)
メインスレッドは下記の用途に使ってはいけません
- 自スレッドをスリープ状態にするタスク
- 停止・待機処理を含むスレッド。(例:ネットワーク通信の受信タスク)
メインスレッド上で同期タスクを実行する事自体は良いのですが、待機や停止の時間がほぼゼロであるものに限ります。(訳者注:1つの処理ステップが長時間を費やす処理は、サーバ自体をその間待機状態に置いてしまうため、メインスレッド上で行うべきではない事を説明しています。)
非同期タスク
非同期タスクは、サーバのメインスレッド以外のスレッドによって実行されます。専用のタスクとして実行されるため、同期タスクで説明したような問題を引き起こすことなく、自タスクを停止・スリープ状態にする事ができます。この特性は、同期タスクの真逆に相当します。
非同期タスクは下記の用途に利用できます
- スケジューラメソッドの呼び出し
- プラグインAPIを利用しないタスク
非同期タスクは下記の用途に利用しなければなりません
- 自スレッドをスリープ状態にするタスク
- 停止・待機処理を含むスレッド。(例:ネットワーク通信の受信タスク)
非同期タスクは下記の用途に利用してはいけません
- Bukkit APIのメソッドを呼び出すタスク(スレッドセーフな方法を除いては、下記参照)
タスクの種類
タスクには、連続タスク, 遅延タスク, 戻り値を返すタスク, の3種類があります。 APIのインタフェースの仕様については[こちら]を参照して下さい。
遅延タスク
一定の遅延を置いてから実行されるタスクです。遅延時間にはゼロを指定可能です。
具体例
This submits a task to the main thread to be executed after 3 seconds.
myPlugin.getServer().getScheduler().scheduleSyncDelayedTask(myPlugin, new Runnable() { 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");
was executed by another thread, it could cause problems since the broadcastMessage method is being executed by another thread.
繰り返しタスク
繰り返し実行されるタスクです。遅延時間も設定可能です。
具体例
This submits a task to an async thread to be executed after 3 seconds with a period of 10 seconds.
myPlugin.getServer().getScheduler().scheduleAsyncRepeatingTask(myPlugin, new Runnable() { public void run() { System.out.println("This message is printed by an async thread"); } }, 60L, 200L);
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.
戻り値を返すタスク
スケジューラから戻り値を返す事ができるタスクです。メインスレッドから実行可能なタスクです。
この仕組みの目的は、他タスクから呼ばれたAPIのメソッドに戻り値を返させる事です。
スケジューラは、戻り値として返されるであろうオブジェクトを取得可能にします。
具体例
Future<String> returnFuture = myPlugin.getServer().getScheduler().callSyncMethod(myPlugin, new Callable<String>() { public String call() { return "This is the string to return"; } }); 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.
メインスレッドからの利用
この方法は非推奨です。 この仕組みは、メインスレッドから利用される事を想定したものではありません。
.get()
メソッドを利用している場合、メインスレッドがこのタスクを完了するまでの間、現行スレッド(=メインスレッド)をスリープ状態にします。
どうしてもメインスレッド上で使用する必要がある場合は、返されるであろうスケジューラの戻り値に対する.get()
メソッドを呼び出す前に、.isDone()
メソッドをチェックしなければなりません。さもなくばメインスレッドは、メインスレッド自身がタスクを完了させるまでスリープ状態になります。
Thread Safe API Methods
Bukkit API methods which are thread safe are:
- All the scheduler methods
- Bukkit.getServer()
- Server.getBukkitVersion()
- World.getUID()
- World.getMaxHeight()
- World.getSeed()
- World.getBlockTypeIdAt(int x, int y, int z)
- Entity.getEntityId()
- Entity.getUniqueId()
- This list is not complete.