提供: Minecraft Modding Wiki
移動先: 案内検索
(Thread Model)
(Synchronous Tasks)
32行目: 32行目:
 
少数のBukkitAPIはスレッドセーフです。あなたのプラグインが使っているAPIがスレッドセーフなものである事を確認していない限り、基本的にBukkitAPIの命令はスレッドセーフではないものとして開発して下さい
 
少数のBukkitAPIはスレッドセーフです。あなたのプラグインが使っているAPIがスレッドセーフなものである事を確認していない限り、基本的にBukkitAPIの命令はスレッドセーフではないものとして開発して下さい
  
==== 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> メインスレッドは下記の用途に'''使えます'''
 +
* スケジューラメソッドの呼び出し
 +
** 将来、スケジューラの戻り値の仕様が変更される可能性があるため注意して下さい(下記参照)
 +
*停止・待機処理を行わないタスク
  
<br> The main thread CAN be used for
+
<br> メインスレッドは下記の用途に'''使わなくてはいけません'''
 +
*Bukkit APIのメソッドを呼び出すタスク(スレッドセーフな方法を除いては、下記参照)
  
*Scheduler method calls
+
<br> メインスレッドは下記の用途に'''使ってはいけません'''
**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)
+
メインスレッド上で同期タスクを実行する事自体は良いのですが、待機や停止の時間がほぼゼロであるものに限ります。(訳者注:1つの処理ステップが長時間を費やす処理は、サーバ自体をその間待機状態に置いてしまうため、メインスレッド上で行うべきではない事を説明しています。)
 
 
<br> The main thread MUST NOT be used for
 
 
 
*Tasks which put the current thread to sleep
 
**This includes tasks which block, i.e. network read tasks
 
 
 
<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.
 
  
 
==== Asynchronous Tasks<br>  ====
 
==== Asynchronous Tasks<br>  ====

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

スケジューラチュートリアル

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

主な注意事項

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

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

Tutorial

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

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

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

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

Thread Model

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

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

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

メインスレッドは、サーバーのClock-Tickを処理します。他タスクこのスレッドは、他のClock-Tickを実行可能とするために、秒間20回のスリープを実行します。

少数のBukkitAPIはスレッドセーフです。あなたのプラグインが使っているAPIがスレッドセーフなものである事を確認していない限り、基本的にBukkitAPIの命令はスレッドセーフではないものとして開発して下さい

同期タスク

サーバのメインスレッドが実行するタスクです。

重要: このスレッドが停止すると、サーバがフリーズします。


メインスレッドは下記の用途に使えます

  • スケジューラメソッドの呼び出し
    • 将来、スケジューラの戻り値の仕様が変更される可能性があるため注意して下さい(下記参照)
  • 停止・待機処理を行わないタスク


メインスレッドは下記の用途に使わなくてはいけません

  • Bukkit APIのメソッドを呼び出すタスク(スレッドセーフな方法を除いては、下記参照)


メインスレッドは下記の用途に使ってはいけません

  • 自スレッドをスリープ状態にするタスク
    • 停止・待機処理を含むスレッド。(例:ネットワーク通信の受信タスク)


メインスレッド上で同期タスクを実行する事自体は良いのですが、待機や停止の時間がほぼゼロであるものに限ります。(訳者注:1つの処理ステップが長時間を費やす処理は、サーバ自体をその間待機状態に置いてしまうため、メインスレッド上で行うべきではない事を説明しています。)

Asynchronous Tasks

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.


An async thread CAN be used for

  • Scheduler method calls
  • Other tasks which don't access the plugin API


An async thread MUST be used for

  • Tasks which put the current thread to sleep
    • This includes tasks which block, i.e. network read tasks


An async thread MUST NOT be used for

  • Tasks which call Bukkit API methods (except thread safe method, see below)


Task Types

There are 3 types of task, repeating tasks, delayed tasks, and tasks which return a value.

The API interface is described [here]

Delayed Tasks

Tasks can be submitted to be executed after a delay. This delay can be set to zero.

Example

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.

Repeating Tasks

Tasks can be submitted to be repeated. An initial delay is also set.

Example

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.

Tasks which return a value

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.

Example
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.

Use From The Main Thread

This is NOT recommended.

This system isn't intended to be used from the main thread.

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.

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).

Thread Safe API Methods

Bukkit API methods which are thread safe are:

テンプレート:Languages