Scheduler Programming/ko

이 자습서에서는 Bukkit에서 제공하는 스케줄러를 이용하는 방법을 배울 것입니다. 스케줄러는 당신의 코드가 나중에 실행되도록 지연시킬 수 있습니다. This is not the same as registering a Listener, a block of code which is executed in response to an event in the game. Blocks of code may also be scheduled to be executed repeatedly at a fixed interval, with or without a delay. They will continue to execute until completed, or canceled, or your plugin is disabled.

When using BukkitRunnable, with a separate class, scheduling work occurs in two steps for the programmer.

1. Define the work to be done, see the section Defining Work
2. Notify Bukkit when the work should be executed, see the section Scheduling Work

Alternatively, work can be scheduled directly with the scheduler, this also occurs in two steps for the programmer.

1. Define the work to be done, in a Runnable or Callable
2. Then directly scheduling the work with the Bukkit Scheduler, see the section BukkitScheduler

# BukkitRunnable

BukkitRunnable은 Runnable의 추상 클래스 구현체입니다. 이 클래스는 Runnable이 지원하지 않는 기능들도 지원하는데, 예로, 기존 Runnable과 달리 BukkitRunnable은 자신이 계획한 태스크라면 중간에 동작을 취소할 수 있습니다. BukkitRunnable은 스케줄러가 아니며, 스케줄러 코드를 포함하고 있지 않습니다. 또한 스케줄러에 비해 생성 시간이 적게 걸리므로 플러그인을 개발할 시, Runnable과 BukkitScheduler를 사용해 작업을 계획하는 것 대신 BukkitRunnable을 생성하여 사용하는 게 권장됩니다.

*자세한 내용은 BukkitRunnable JavaDocs을 참고하십시오.*
## 작업 정의하기

플러그인은 BukkitRunnable을 사용하기 전에 클래스를 상속하여 작업을 정의해야 합니다. 이 클래스의 run 메소드가 바로 이 작업이 실행되는 부분입니다.

### 간단한 예제

다음은 실행할 수 있는 태스크의 예제입니다.

>
> ```
> import org.bukkit.Bukkit;
> import org.bukkit.plugin.java.JavaPlugin;
> import org.bukkit.scheduler.BukkitRunnable;
>
> public class ExampleTask extends BukkitRunnable {
>
>  private final JavaPlugin plugin;
>
>  public ExampleTask(JavaPlugin plugin) {
>  this.plugin = plugin;
>  }
>
>  @Override
>  public void run() {
>  // What you want to schedule goes here
>  plugin.getServer().broadcastMessage("Welcome to Bukkit! Remember to read the documentation!");
>  }
>
> }
>
> ```
>

### 동작 취소 예제

다음은 특정 횟수 이상 실행되면 자동으로 자기 자신을 취소하는 태스크의 예제입니다.

>
> ```
> import org.bukkit.plugin.java.JavaPlugin;
> import org.bukkit.scheduler.BukkitRunnable;
>
> public class ExampleSelfCancelingTask extends BukkitRunnable {
>
>  private final JavaPlugin plugin;
>
>  private int counter;
>
>  public ExampleSelfCancelingTask(JavaPlugin plugin, int counter) {
>  this.plugin = plugin;
>  if (counter <= 0) {
>  throw new IllegalArgumentException("counter must be greater than 0");
>  } else {
>  this.counter = counter;
>  }
>  }
>
>  @Override
>  public void run() {
>  // What you want to schedule goes here
>  if (counter > 0) {
>  plugin.getServer().broadcastMessage("Commence greeting in " + counter--);
>  } else {
>  plugin.getServer().broadcastMessage("Welcome to Bukkit! Remember to read the documentation!");
>  this.cancel();
>  }
>  }
>
> }
>
> ```
>

## Scheduling Work

After defining the task, the plugin needs to schedule the task. BukkitRunnables are scheduled when the desired run method is invoked on an instance of the task. The list of methods for BukkitRunnable can be found in the Javadocs for BukkitRunnable. The different run methods all return a  BukkitTask object

### Example

This is an example of a plugin which registers a listener and when a player joins, schedules a task to be run 20 ticks later.

>
> ```
> import org.bukkit.event.EventHandler;
> import org.bukkit.event.Listener;
> import org.bukkit.event.player.PlayerJoinEvent;
> import org.bukkit.plugin.java.JavaPlugin;
> import org.bukkit.scheduler.BukkitRunnable;
> import org.bukkit.scheduler.BukkitTask;
>
> public final class ExamplePlugin extends JavaPlugin {
>
>  @Override
>  public void onEnable() {
>  new ExampleListener(this);
>  }
> }
>
> class ExampleListener implements Listener {
>
>  private final ExamplePlugin plugin;
>
>  public ExampleListener(ExamplePlugin plugin) {
>  this.plugin = plugin;
>  this.plugin.getServer().getPluginManager().registerEvents(this, plugin);
>  }
>
>  @EventHandler
>  public void onJoin(PlayerJoinEvent event) {
>  // Create the task and schedule to run it once, after 20 ticks
>  BukkitTask task = new ExampleTask(this.plugin).runTaskLater(this.plugin, 20);
>  }
>
> }
>
> ```
>

### Self-Canceling Example

This is example takes the above ExampleSelfCancelingTask and schedules it to run every 20 ticks after waiting 10 ticks.

>
> ```
> import org.bukkit.event.EventHandler;
> import org.bukkit.event.Listener;
> import org.bukkit.event.player.PlayerJoinEvent;
> import org.bukkit.plugin.java.JavaPlugin;
> import org.bukkit.scheduler.BukkitRunnable;
> import org.bukkit.scheduler.BukkitTask;
>
> public final class ExamplePlugin extends JavaPlugin {
>
>  @Override
>  public void onEnable() {
>  new ExampleListener(this);
>  }
> }
>
> class ExampleListener implements Listener {
>
>  private final ExamplePlugin plugin;
>
>  public ExampleListener(ExamplePlugin plugin) {
>  this.plugin = plugin;
>  this.plugin.getServer().getPluginManager().registerEvents(this, plugin);
>  }
>
>  @EventHandler
>  public void onJoin(PlayerJoinEvent event) {
>  // Create the task and schedule
>  BukkitTask task = new ExampleSelfCancelingTask(this.plugin, 5).runTaskTimer(this.plugin, 10, 20);
>  }
>
> }
>
> ```
>

### Anonymous BukkitRunnable Example

An anonymous BukkitRunnable will allow you to schedule a task, without creating a new class with a name. This examples combines the above two basic examples.

>
> ```
> import org.bukkit.event.EventHandler;
> import org.bukkit.event.Listener;
> import org.bukkit.event.player.PlayerJoinEvent;
> import org.bukkit.plugin.java.JavaPlugin;
> import org.bukkit.scheduler.BukkitRunnable;
> import org.bukkit.scheduler.BukkitTask;
>
> public final class ExamplePlugin extends JavaPlugin {
>
>  @Override
>  public void onEnable() {
>  new ExampleListener(this);
>  }
> }
>
> class ExampleListener implements Listener {
>
>  private final ExamplePlugin plugin;
>
>  public ExampleListener(ExamplePlugin plugin) {
>  this.plugin = plugin;
>  this.plugin.getServer().getPluginManager().registerEvents(this, plugin);
>  }
>
>  @EventHandler
>  public void onJoin(PlayerJoinEvent event) {
>  // Create the task anonymously and schedule to run it once, after 20 ticks
>  new BukkitRunnable() {
>
>  @Override
>  public void run() {
>  // What you want to schedule goes here
>  plugin.getServer().broadcastMessage(
>  "Welcome to Bukkit! Remember to read the documentation!");
>  }
>
>  }.runTaskLater(this.plugin, 20);
>  }
>
> }
>
> ```
>

# BukkitScheduler

The BukkitScheduler allows plugins to schedule a Runnable and/or a Callable , for execution at a later time. The list of methods for BukkitScheduler can be found in the Javadocs for BukkitScheduler.

 **Note**: Plugins should not schedule a BukkitRunnable with the scheduler, instead they should run the BukkitRunnable with the desired schedule.
### Example

Example for directly scheduling an anonymous Runnable with the BukkitScheduler to run after 20 ticks.

>
> ```
> import org.bukkit.Bukkit;
> import org.bukkit.plugin.java.JavaPlugin;
> import org.bukkit.scheduler.BukkitScheduler;
>
> public final class ExamplePlugin extends JavaPlugin {
>  public void onEnable() {
>  BukkitScheduler scheduler = getServer().getScheduler();
>  scheduler.scheduleSyncDelayedTask(this, new Runnable() {
>  @Override
>  public void run() {
>  // Do something
>  }
>  }, 20L);
>  }
> }
>
> ```
>

### Repeating Example

Example for directly scheduling an anonymous Runnable with the BukkitScheduler to run every twenty ticks, forever, starting from when you schedule it.

>
> ```
> import org.bukkit.Bukkit;
> import org.bukkit.plugin.java.JavaPlugin;
> import org.bukkit.scheduler.BukkitScheduler;
>
> public final class ExamplePlugin extends JavaPlugin {
>  public void onEnable() {
>  BukkitScheduler scheduler = getServer().getScheduler();
>  scheduler.scheduleSyncRepeatingTask(this, new Runnable() {
>  @Override
>  public void run() {
>  // Do something
>  }
>  }, 0L, 20L);
>  }
> }
>
> ```
>

## BukkitTask

A BukkitTask object is returned whenever a Runnable is scheduled. This object represents the task the scheduled task being executed by the scheduler. For more information see, Javadocs for BukkitTask.

## Callable and Future

A Callable given to the scheduler to call synchronously returns a Future. These are standard Java classes, for more information see, Javadocs for Callable and Javadocs for Future

# Tips for thread safety

The Bukkit API, with the exception of the scheduler package, is not thread safe nor guaranteed to be thread safe.

1. Asynchronous tasks should never access any API in Bukkit.
2. Do not access or modify shared collections from your asynchronous tasks. Normal collections are not thread-safe. This also applies to objects which are not thread safe.
3. An asynchronous task can schedule a synchronous task.
4. A synchronous task can schedule an asynchronous task.
5. If you want to schedule something at a fixed time, by calculating how many ticks until that point in time, you should use an asynchronous task. If you don't, lag will increase the delay.