提供: Minecraft Modding Wiki
移動先: 案内検索
(スレッドの種類)
(タスクの種類)
88行目: 88行目:
 
APIのインタフェースの仕様については[[https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bukkit/scheduler/BukkitScheduler.java こちら]]を参照して下さい。
 
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.  
 
This submits a task to the main thread to be executed after 3 seconds.  
111行目: 111行目:
 
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.  
  
==== 繰り返しタスク ====
+
=== 繰り返しタスク ===
  
 
繰り返し実行されるタスクです。遅延時間も設定可能です。
 
繰り返し実行されるタスクです。遅延時間も設定可能です。
  
====== 具体例 ======
+
==== 具体例 ====
  
 
This submits a task to an async thread to be executed after 3 seconds with a period of 10 seconds.  
 
This submits a task to an async thread to be executed after 3 seconds with a period of 10 seconds.  
130行目: 130行目:
 
The above code will print "This message is printed by an async thread" every 10 seconds.  
 
The above code will print "This message is printed by an async thread" every 10 seconds.  
  
==== 戻り値を返すタスク ====
+
=== 戻り値を返すタスク ===
  
 
スケジューラから戻り値を返す事ができるタスクです。メインスレッドから実行可能なタスクです。
 
スケジューラから戻り値を返す事ができるタスクです。メインスレッドから実行可能なタスクです。
138行目: 138行目:
 
スケジューラは、戻り値として返されるであろうオブジェクトを取得可能にします。
 
スケジューラは、戻り値として返されるであろうオブジェクトを取得可能にします。
  
====== 具体例 ======
+
==== 具体例 ====
  
 
  Future<String> returnFuture = myPlugin.getServer().getScheduler().callSyncMethod(myPlugin, new Callable<String>() {
 
  Future<String> returnFuture = myPlugin.getServer().getScheduler().callSyncMethod(myPlugin, new Callable<String>() {
162行目: 162行目:
 
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.  
 
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.  
  
====== メインスレッドからの利用 ======
+
===== メインスレッドからの利用 =====
  
 
この方法は'''非推奨'''です。
 
この方法は'''非推奨'''です。

2012年6月24日 (日) 03:11時点における版

スケジューラの解説

この解説では、Bukkitのスケジューラの利用方法を説明しています。

主な注意事項

主な注意事項は次の2点です。

  • 他のスレッドからAPIのメソッドを(一部例外あり)を呼び出さない
  • メインのスレッドをスリープ状態にしてはならない

解説

スケジューラは次の3種類のタスクをオプションとして提供しています。

  • 遅延タスク(Delayed Task)
  • 連続タスク(Repeating Task)
  • 戻り値を返すタスク

これらのタスクは2種類のスレッドとして実行する事ができます。

  • メインサーバスレッド
  • 専用スレッド

スレッドの種類

スケジューラにどのスレッドタイプを利用すれば良いかが、最も重要な問題です。
間違ったスレッドタイプを利用すると、検出が困難な障害を断続的に発生させる原因となります。
また、そのような障害は試験サーバでは発生せず、頻繁に連続稼動しているサーバでのみ発生する場合がある等、
再現性が低い障害となる場合もあるため、原因の特定を更に困難にします。

Minecraftサーバはマルチスレッドであり、
一つのメインサーバーのスレッドと、他のヘルパースレッドが存在します。

多くのデータ構造は、サーバのメインスレッドからのみアクセスされます。
別のスレッドからこれらのデータを変更しようとすると、
2つのスレッドが同時にデータにアクセスする事になるため、
データ破損を引き起こす可能性があります。

メインスレッドは、サーバーのCPU時間の配分を処理します。
このスレッドは、他のタスクへCPU時間を配分するために、秒間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:

テンプレート:Languages