提供: Minecraft Modding Wiki
この編集を取り消せます。
下記の差分を確認して、本当に取り消していいか検証してください。よろしければ変更を保存して取り消しを完了してください。
最新版 | 編集中の文章 | ||
1行目: | 1行目: | ||
− | == | + | == スケジューラの解説 == |
+ | この解説では、Bukkitのスケジューラの利用方法を説明しています。 | ||
− | + | == 主な注意事項 == | |
− | |||
− | |||
− | |||
− | + | 主な注意事項は次の2点です。 | |
− | + | * 他のスレッドからAPIのメソッドを(一部例外あり)を呼び出さない | |
− | + | * メインのスレッドをスリープ状態にしてはならない | |
− | == | + | == 解説 == |
− | + | スケジューラは次の3種類のタスクをオプションとして提供しています。 | |
− | + | *遅延タスク(Delayed Task) | |
+ | *連続タスク(Repeating Task) | ||
+ | *戻り値を返すタスク | ||
− | + | これらのタスクは2種類のスレッドとして実行する事ができます。 | |
+ | *メインサーバスレッド | ||
+ | *専用スレッド | ||
− | + | === スレッドの種類 === | |
− | + | スケジューラにどのスレッドタイプを利用すれば良いかが、最も重要な問題です。 | |
− | + | 間違ったスレッドタイプを利用すると、検出が困難な障害を断続的に発生させる原因となります。また、そのような障害は試験サーバでは発生せず、頻繁に連続稼動しているサーバでのみ発生する場合がある等、再現性が低い障害である場合もあるため、原因の特定を更に困難にします。 | |
− | |||
− | |||
− | + | Minecraftサーバはマルチスレッドであり、一つのメインサーバーのスレッドと他のヘルパースレッドが存在します。 | |
− | + | 多くのデータ構造は、サーバのメインスレッドからのみアクセスされます。別のスレッドからこれらのデータを変更しようとすると、2つのスレッドが同時にデータにアクセスする事になるため、データ破損を引き起こす可能性があります。 | |
− | + | ||
− | + | メインスレッドは、サーバーのClock-Tickを処理します。他タスクこのスレッドは、他のClock-Tickを実行可能とするために、秒間20回のスリープを実行します。 | |
− | + | ||
− | + | 少数のBukkitAPIはスレッドセーフです。あなたのプラグインが使っているAPIがスレッドセーフなものである事を確認していない限り、基本的にBukkitAPIの命令はスレッドセーフではないものとして開発して下さい | |
− | + | ||
− | < | + | ==== 同期タスク ==== |
+ | サーバのメインスレッドが実行するタスクです。 | ||
+ | |||
+ | :'''重要''': '''このスレッドが停止すると、サーバがフリーズします。''' | ||
+ | |||
+ | <br> メインスレッドは下記の用途に'''使えます''' | ||
+ | * スケジューラメソッドの呼び出し | ||
+ | ** 将来、スケジューラの戻り値の仕様が変更される可能性があるため注意して下さい(下記参照) | ||
+ | *停止・待機処理を行わないタスク | ||
+ | |||
+ | <br> メインスレッドは下記の用途に'''使わなくてはいけません''' | ||
+ | *Bukkit APIのメソッドを呼び出すタスク(スレッドセーフな方法を除いては、下記参照) | ||
− | + | <br> メインスレッドは下記の用途に'''使ってはいけません''' | |
+ | *自スレッドをスリープ状態にするタスク | ||
+ | **停止・待機処理を含むスレッド。(例:ネットワーク通信の受信タスク) | ||
− | |||
− | |||
− | |||
− | |||
− | + | メインスレッド上で同期タスクを実行する事自体は良いのですが、待機や停止の時間がほぼゼロであるものに限ります。(訳者注:1つの処理ステップが長時間を費やす処理は、サーバ自体をその間待機状態に置いてしまうため、メインスレッド上で行うべきではない事を説明しています。) | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | ==== 非同期タスク ==== | |
− | + | 非同期タスクは、サーバのメインスレッド以外のスレッドによって実行されます。専用のタスクとして実行されるため、同期タスクで説明したような問題を引き起こすことなく、自タスクを停止・スリープ状態にする事ができます。この特性は、同期タスクの真逆に相当します。 | |
− | |||
− | |||
− | |||
− | + | <br> 非同期タスクは下記の用途に'''利用できます''' | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | < | ||
− | + | *スケジューラメソッドの呼び出し | |
+ | *プラグインAPIを利用しないタスク | ||
− | + | <br> 非同期タスクは下記の用途に'''利用しなければなりません''' | |
− | + | *自スレッドをスリープ状態にするタスク | |
+ | **停止・待機処理を含むスレッド。(例:ネットワーク通信の受信タスク) | ||
− | < | + | <br> 非同期タスクは下記の用途に'''利用してはいけません''' |
− | |||
− | |||
− | + | *Bukkit APIのメソッドを呼び出すタスク(スレッドセーフな方法を除いては、下記参照) | |
− | + | <br> | |
− | + | == タスクの種類 == | |
− | + | There are 3 types of task, repeating tasks, delayed tasks, and tasks which return a value. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | The API interface is described [[https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bukkit/scheduler/BukkitScheduler.java here]] | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | ==== 遅延タスク ==== | ||
− | + | Tasks can be submitted to be executed after a delay. This delay can be set to zero. | |
− | + | ====== 具体例 ====== | |
− | |||
− | |||
− | |||
− | |||
− | + | This submits a task to the main thread to be executed after 3 seconds. | |
− | + | myPlugin.getServer().getScheduler().scheduleSyncDelayedTask(myPlugin, new Runnable() { | |
− | public void | + | |
− | getServer(). | + | 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. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | == | + | ==== 連続タスク ==== |
− | + | Tasks can be submitted to be repeated. An initial delay is also set. | |
− | |||
− | + | ====== 具体例 ====== | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | 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 | + | |
− | + | 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. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | == | + | ==== 戻り値を返すタスク ==== |
− | + | It is possible to submit tasks which return a value to the scheduler. Only submission for execution by the main thread is supported. | |
− | |||
− | |||
− | + | The purpose of this system is to allow API methods that return values to be called by other threads. | |
− | |||
− | + | The scheduler returns a Future object that can be used to obtain the result. | |
− | + | ====== 具体例 ====== | |
− | |||
− | |||
− | |||
− | |||
− | + | 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. | |
− | + | ====== メインスレッドからの利用 ====== | |
− | |||
− | |||
− | |||
− | |||
− | + | この方法は'''非推奨'''です。 | |
− | + | この仕組みは、メインスレッドから利用される事を想定したものではありません。 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | = | + | <code>''.get()''</code>メソッドを利用している場合、メインスレッドがこのタスクを完了するまでの間、現行スレッド(=メインスレッド)をスリープ状態にします。 |
− | + | どうしてもメインスレッド上で使用する必要がある場合は、返されるであろうスケジューラの戻り値に対する<code>''.get()</code>メソッドを呼び出す前に、<code>''.isDone()''</code>メソッドをチェックしなければなりません。さもなくばメインスレッドは、メインスレッド自身がタスクを完了させるまでスリープ状態になります。 | |
− | |||
− | |||
− | == | + | == Thread Safe API Methods == |
− | + | Bukkit API methods which are thread safe are: | |
− | |||
− | |||
− | + | *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}} | |
− | + | [[Category:Tutorials]] | |
− | |||
− |