提供: Minecraft Modding Wiki
この編集を取り消せます。
下記の差分を確認して、本当に取り消していいか検証してください。よろしければ変更を保存して取り消しを完了してください。
最新版 | 編集中の文章 | ||
1行目: | 1行目: | ||
− | == | + | == スケジューラの解説 == |
+ | この解説では、Bukkitのスケジューラの利用方法を説明しています。 | ||
− | + | == 主な注意事項 == | |
− | |||
− | |||
− | |||
− | + | 主な注意事項は次の2点です。 | |
− | + | * 他のスレッドからAPIのメソッドを(一部例外あり)を呼び出さない | |
− | + | * メインのスレッドをスリープ状態にしてはならない | |
− | == | + | == 解説 == |
− | + | スケジューラは次の3種類のタスクをオプションとして提供しています。 | |
− | + | *遅延タスク(Delayed Task) | |
+ | *連続タスク(Repeating Task) | ||
+ | *戻り値を返すタスク | ||
− | + | これらのタスクは2種類のスレッドとして実行する事ができます。 | |
+ | *メインサーバスレッド | ||
+ | *専用スレッド | ||
− | + | === スレッドの種類 === | |
− | + | スケジューラにどのスレッドタイプを利用すれば良いかが、最も重要な問題です。<br> | |
− | < | + | 間違ったスレッドタイプを利用すると、検出が困難な障害を断続的に発生させる原因となります。<br> |
− | + | また、そのような障害は試験サーバでは発生せず、頻繁に連続稼動しているサーバでのみ発生する場合がある等、<br> | |
− | + | 再現性が低い障害となる場合もあるため、原因の特定を更に困難にします。 | |
− | + | Minecraftサーバはマルチスレッドであり、<br> | |
+ | 一つのメインサーバーのスレッドと、他のヘルパースレッドが存在します。 | ||
− | + | 多くのデータ構造は、サーバのメインスレッドからのみアクセスされます。<br> | |
− | + | 別のスレッドからこれらのデータを変更しようとすると、<br> | |
− | + | 2つのスレッドが同時にデータにアクセスする事になるため、<br> | |
− | + | データ破損を引き起こす可能性があります。 | |
− | |||
− | |||
− | < | ||
− | + | メインスレッドは、サーバーのCPU時間の配分を処理します。<br> | |
+ | このスレッドは、他のタスクへCPU時間を配分するために、秒間20回のスリープを実行します。 | ||
− | + | 少数のBukkitAPIはスレッドセーフです。<br> | |
− | + | あなたのプラグインが使っているAPIがスレッドセーフなものである事を確認していない限り、<br> | |
− | + | 基本的にBukkitAPIの命令はスレッドセーフではないものとして開発して下さい | |
− | |||
− | + | ==== 同期タスク ==== | |
− | + | サーバのメインスレッドが実行するタスクです。 | |
− | |||
− | |||
− | |||
− | |||
− | + | :'''重要''': '''このスレッドが停止すると、サーバがフリーズします。''' | |
− | + | <br> メインスレッドは下記の用途に'''使えます''' | |
− | + | * スケジューラメソッドの呼び出し | |
− | + | ** スケジューラの戻り値を取得する際は注意を要します(後方の説明に記載) | |
− | + | *停止・待機処理を行わないタスク | |
− | + | <br> メインスレッドは下記の用途に'''使わなくてはいけません''' | |
− | + | *Bukkit APIのメソッドを呼び出すタスク(スレッドセーフな方法を除く) | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | < | ||
− | + | <br> メインスレッドは下記の用途に'''使ってはいけません''' | |
+ | *自スレッドをスリープ状態にするタスク | ||
+ | **停止・待機処理を含むスレッド。(例:ネットワーク通信の受信タスク) | ||
− | |||
− | ''' | + | メインスレッド上で同期タスクを実行する事自体は良いのですが、<br> |
+ | 待機や停止の時間がほぼゼロであるものに限ります。<br> | ||
+ | :'''訳者注''': 1つの処理ステップが長時間を費やす処理は、サーバ自体をその間待機状態に置いてしまうため、メインスレッド上で行うべきではない事を説明しています。 | ||
− | + | ==== 非同期タスク ==== | |
− | |||
− | |||
− | + | 非同期タスクは、サーバのメインスレッド以外のスレッドによって実行されます。専用のタスクとして実行されるため、同期タスクで説明したような問題を引き起こすことなく、自タスクを停止・スリープ状態にする事ができます。この特性は、同期タスクの真逆に相当します。 | |
− | + | <br> 非同期タスクは下記の用途に'''利用できます''' | |
− | + | *スケジューラメソッドの呼び出し | |
+ | *プラグインAPIを利用しないタスク | ||
− | + | <br> 非同期タスクは下記の用途に'''利用しなければなりません''' | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | *自スレッドをスリープ状態にするタスク | |
− | + | **停止・待機処理を含むスレッド。(例:ネットワーク通信の受信タスク) | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | <br> 非同期タスクは下記の用途に'''利用してはいけません''' | ||
− | + | *Bukkit APIのメソッドを呼び出すタスク(スレッドセーフな方法を除いては、下記参照) | |
− | < | + | <br> |
− | |||
− | |||
− | |||
− | |||
− | + | == タスクの種類 == | |
+ | タスクには、連続タスク, 遅延タスク, 戻り値を返すタスク, の3種類があります。 | ||
− | + | APIのインタフェースの仕様については[[https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bukkit/scheduler/BukkitScheduler.java こちら]]を参照して下さい。 | |
− | |||
− | |||
− | |||
− | + | === 遅延タスク === | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | 一定の遅延を置いてから実行されるタスクです。遅延時間にはゼロを指定可能です。 | |
− | + | ==== 具体例 ==== | |
− | |||
+ | This submits a task to the main thread to be executed after 3 seconds. | ||
<blockquote><source lang="java"> | <blockquote><source lang="java"> | ||
− | + | myPlugin.getServer().getScheduler().scheduleSyncDelayedTask(myPlugin, new Runnable() { | |
− | |||
− | |||
− | |||
− | |||
− | public | + | public void run() { |
+ | getServer().broadcastMessage("This message is broadcast by the main thread"); | ||
+ | } | ||
+ | }, 60L); | ||
+ | </source></blockquote> | ||
+ | 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 | |
− | + | <blockquote><source lang="java"> | |
− | + | getServer().broadcastMessage("This message is broadcast by an async thread"); | |
− | + | </source></blockquote> | |
+ | 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. | |
− | + | <blockquote><source lang="java"> | |
− | + | myPlugin.getServer().getScheduler().scheduleAsyncRepeatingTask(myPlugin, new Runnable() { | |
− | + | ||
− | + | public void run() { | |
− | + | System.out.println("This message is printed by an async thread"); | |
− | + | } | |
− | + | }, 60L, 200L); | |
− | |||
− | |||
</source></blockquote> | </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. | |
− | |||
− | |||
− | + | === 戻り値を返すタスク === | |
− | |||
− | + | スケジューラから戻り値を返す事ができるタスクです。メインスレッドから実行可能なタスクです。 | |
− | + | この仕組みの目的は、他タスクから呼ばれたAPIのメソッドに戻り値を返させる事です。 | |
+ | |||
+ | スケジューラは、戻り値として返されるであろうオブジェクトを取得可能にします。 | ||
+ | |||
+ | ==== 具体例 ==== | ||
<blockquote><source lang="java"> | <blockquote><source lang="java"> | ||
− | + | 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(); | |
− | |||
} | } | ||
</source></blockquote> | </source></blockquote> | ||
− | === | + | 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.... |