Khi chúng ta phát triển ứng dụng với java thỉnh thoảng chúng ta sẽ gặp những bài toán tạo một xử lý chạy trên background trong một khoảng thời gian.
Ví dụ: gửi dữ liệu lên server hay clean application...
Trong bài viết này mình xin giới thiệu với các bạn 3 cách để có thể giải quyết bài toán này trên java:

  1. Sử dụng Thread
  2. Sử dụng TimerTask
  3. Sử dụng ScheduledExecutorService

Sử dụng Thread

Đây được xem là cách đơn giản và khá quen thuộc đối với nhiều lập trình viên. Chúng ta chỉ cần tạo một Thread và cho nó chạy mãi mãi bằng việc dùng một vòng lặp vô hạn và sử dụng Thread.sleep(timeInterval) để delay task

public class Task  {
public static void main(String[] args) {
  // run in a second
  final long timeInterval = 1000;
  Runnable runnable = new Runnable() {
  public void run() {
    while (true) {
      // ------- code for task to run
      System.out.println("Hello !!");
      // ------- ends here
      try {
       Thread.sleep(timeInterval);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      }
    }
  };
  Thread thread = new Thread(runnable);
  thread.start();
  }
}

Việc bắt và xử lý ngoại lệ InterruptedException là cần thiết vì nếu có ngoại lệ xảy ra thì task sẽ bị dừng lại ngay lập tức .

Sử dụng TimerTask

Sử dụng Thread là một cách nhanh và cài đặt khá dễ dàng, tuy nhiên nó lại có một số hạn chế như:

  • Không kiểm soát được lúc công việc bắt đầu hoặc bị hủy
  • Không hỗ trợ time delay cho lần thực hiện đầu tiên
    Khi sử dụng TimerTask, nó có thể giúp chúng ta giải quyết được những vấn đề trên.
    Để cài đặt chúng ta sẽ sử dụng 2 đối tượng là Timer để lập lịch và TimerTask được dùng để thực hiện công việc trong hàm run()
public class Task {
  public static void main(String[] args) {
    TimerTask task = new TimerTask() {
      @Override
      public void run() {
        // task to run goes here
        System.out.println("Hello !!!");
      }
    };
    Timer timer = new Timer();
    long delay = 0;
    long intevalPeriod = 1 * 1000; 
    // schedules the task to be run in an interval 
    timer.scheduleAtFixedRate(task, delay,
                                intevalPeriod);
  } // end of main
}

Sử dụng ScheduledExecutorService

Được giới thiệu trong gói java.util.concurrent từ java 5. ScheduledExecutorService là một cách được ưa thích để giải quyết bài toán của chúng ta
Việc sử dụng ScheduledExecutorService sẽ mang lại cho chúng ta một số lợi ích như:

  • Dễ dàng cho việc delay lần thực hiện đầu tiên
  • Cung cấp những quy định cho việc cung cấp thời gian lặp lại task

ScheduledExecutorService có 3 method chính đó là:schedule(), scheduleWithFixedDelay(), scheduleAtFixedRate().
Thường chúng ta sẽ sử dụng 2 phuơng thức đó là: scheduleWithFixedDelay() và scheduleAtFixedRate().

Nói qua về sự khách nhau giữa 2 method này thì scheduleAtFixedRate()scheduleWithFixedDelay() đều nhận vào những tham số giống nhau đó là một Runnable để thực thi task, thời gian delay trong lần thực thi đầu tiên, thời gian nghỉ và tham số cuối cùng là đơn vị thời gian. Tuy nhiên chúng lại có những điểm khác nhau về cách thực thi, scheduleWithFixedDelay() sẽ đợi cho task thực thi xong và tiếp tục chờ hết thời gian nghỉ sau đó mới thực thi lại task đó, còn scheduleAtFixedRate() sẽ thực thi task sau mỗi một khoảng thời gian nghỉ.

public static void main(String[] args) {
    Runnable runnable = new Runnable() {
      public void run() {
        // task to run goes here
        System.out.println("Hello !!");
      }
    };
    ScheduledExecutorService service = Executors
                    .newSingleThreadScheduledExecutor();
    service.scheduleAtFixedRate(runnable, 0, 1, TimeUnit.SECONDS);
  }

Lưu ý:
Khi sử dụng ScheduledExecutorServiceTimerTask chúng ta sẽ tránh được InterruptedException tuy nhiên nếu trong hàm run() có xảy ra ngoại lệ thì task cũng sẽ bị dừng lại vì vậy chúng ta cần xem xét đến các trường hợp gây ra ngoại lệ và sử lý bắt ngoại lệ tại đây.
Hy vọng những cách trên có thể hữu ích với các bạn!!!
Tham khảo:
https://developer.android.com/reference/java/util/concurrent/ScheduledThreadPoolExecutor.html