ScheduledExecutorService 使い方メモ


# 図で比べるとこんなかんじ
![executors.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28302/b7b26bf5-9441-5265-9d12-1168b69c9d6e.jpeg)


# schedule() - 指定した時間待機してから処理を実行する
```java:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Main {
    
    public static void main(String[] args) throws Exception {
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        
        service.schedule(() -> {
            System.out.println("end!!");
            service.shutdown();
            System.exit(0);
        }, 1, TimeUnit.SECONDS);
        
        int count = 0;
        while (true) {
            Thread.sleep(100);
            System.out.println((++count) * 100 + " ms");
        }
    }
}
```

```text:実行結果
100 ms
200 ms
300 ms
400 ms
500 ms
600 ms
700 ms
800 ms
900 ms
1000 ms
end!!
```

# scheduleAtFixedRate() - 一定時間ごとに処理を実行する
```java:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class Main {
    public static void main(String... args) throws Exception {
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

        AtomicInteger number = new AtomicInteger(0);
        service.scheduleAtFixedRate(() -> {
            int n = number.getAndIncrement();
            System.out.println("begin(" + n + ")");
            sleep(Math.max(1, 3-n));
            System.out.println("end(" + n + ")");
        }, 2, 2, TimeUnit.SECONDS);

        int count = 0;
        while (true) {
            TimeUnit.SECONDS.sleep(1);
            System.out.println((++count) + " s");
        }
    }

    private static void sleep(long seconds) {
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException  e) {}
    }
}
```

- 第一引数の処理時間が、３秒→２秒→１秒→１秒→１秒...と徐々に短くなるように調整している


```text:実行結果
1 s
begin(0)
2 s
3 s
4 s
end(0)
begin(1)　←直前の処理が終了するまで待機させられている
5 s
6 s
end(1)
begin(2)
7 s
end(2)
begin(3)
8 s
end(3)
9 s
begin(4)
10 s
end(4)
11 s
begin(5)
12 s
end(5)
13 s
begin(6)
14 s
end(6)
15 s
```

- 第二引数が、初回の待機時間。
- 第三引数が、二回目以降の待機時間。
- <del>第一引数の処理が完了しなくても、待機時間がすぎればガンガン処理が呼ばれる。</del>（2020年3月11日、コメントで指摘があり修正）
- 第三引数で指定した間隔で、第一引数に指定した処理が実行される
    - ただし、第一引数の処理時間が第三引数で指定した時間よりも長くなると、次の処理は直前の処理が終了するまで待機させられる
    - つまり、第一引数の処理が並列に実行されることはない
    - 実行が待機させられた処理は、直前の処理が終了したら即座に実行される

# scheduleWithFixedDelay() - 繰り返し処理の完了を待ってから一定時間待機を繰り返す
```java
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Main {
    
    private static int n = 0;
    
    public static void main(String[] args) throws Exception {
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        
        service.scheduleWithFixedDelay(() -> {
            System.out.println("begin(" + n + ")");
            sleep(1000);
            System.out.println("end(" + n + ")");
            n++;
        }, 2, 1, TimeUnit.SECONDS);
        
        int count = 0;
        while (true) {
            sleep(1000);
            System.out.println((++count) + " s");
        }
    }
    
    private static void sleep(long ms) {
        try {
            Thread.sleep(ms);
        } catch (InterruptedException e) {}
    }
}
```

```text:実行結果
1 s
2 s
begin(0)
3 s
end(0)
4 s
begin(1)
5 s
end(1)
6 s
begin(2)
7 s
end(2)
8 s
begin(3)
9 s
end(3)
10 s
```

- 第二引数が、初回の待機時間。
- 第一引数の処理の完了を待機してから、第三引数で指定した時間待機して、次の処理を実行する


# 参考
- [ScheduledExecutorService (Java Platform SE 8 )](http://docs.oracle.com/javase/jp/8/docs/api/java/util/concurrent/ScheduledExecutorService.html#scheduleAtFixedRate-java.lang.Runnable-long-long-java.util.concurrent.TimeUnit-)