STACKJAVA

Code ví dụ Callable, Future, Executors trong Java

Code ví dụ Callable, Future, Executors trong Java.

(Xem thêm: So sánh Future và CompletableFuture trong Java)

Thay vì tạo thread bằng việc Extend Thread hoặc implement Runable và tự quản lý số lượng thread. Thì ta có một hướng tiếp cận khác đó là sử dụng Callable và Future. (Cho phép hủy các thread, kiểm tra thread đã hoàn thành chưa, quản lý số thread chạy cùng lúc …)

Callable, Future, Executors là gì?

Code ví dụ Callable, Future, Executors trong Java.

Ví dụ mình muốn thực hiện nhiều phép tính tổng 2 số nguyên cùng lúc:

Đầu tiên mình tạo một class thực hiện implement Callable với kiểu trả về là Integer và implement phương thức tính tổng

package stackjava.com.futureTutorial;

import java.util.concurrent.Callable;

public class Calculator implements Callable<Integer> {

  private int a;
  private int b;

  public Calculator(int a, int b) {
    this.a = a;
    this.b = b;
  }
  
	public int sum() {
		int sum = this.a + this.b;
		System.out.println("result: " + a + " + " + b + " = " + sum);
		return sum;
	}

  @Override
  public Integer call() throws Exception {
    return this.sum();
  }

}

Ví dụ 1: Bây giờ mình sử dụng Executors để tạo một thread pool chứa các các đối tượng Calculator

package stackjava.com.futureTutorial;

import java.util.concurrent.*;

public class Demo1 {
  public static void main(String[] args) throws InterruptedException, ExecutionException {
    Calculator c1 = new Calculator(1, 2);
    Calculator c2 = new Calculator(1, 3);
    Calculator c3 = new Calculator(2, 3);

    ExecutorService executor = Executors.newFixedThreadPool(10);
    Future<Integer> f1 = executor.submit(c1);
    Future<Integer> f2 = executor.submit(c2);
    Future<Integer> f3 = executor.submit(c3);
    System.out.println("Done");
    
    executor.shutdown();
  }
}

Chạy ví dụ trên ta có kết quả sau:

Done
result: 2 + 3 = 5
result: 1 + 2 = 3
result: 1 + 3 = 4

Kết quả hiển thị không theo thứ tự được submit vào executor vì nó chạy cùng lúc.

Ví dụ 2: Bây giờ mình muốn in ra kết quả của c1 thì mình sẽ gọi f1.get()

package stackjava.com.futureTutorial;

import java.util.concurrent.*;

public class Demo2 {
  public static void main(String[] args) throws InterruptedException, ExecutionException {
    Calculator c1 = new Calculator(1, 2);
    Calculator c2 = new Calculator(1, 3);
    Calculator c3 = new Calculator(2, 3);

    ExecutorService executor = Executors.newFixedThreadPool(10);
    Future<Integer> f1 = executor.submit(c1);
    System.out.println(f1.get());
    Future<Integer> f2 = executor.submit(c2);
    Future<Integer> f3 = executor.submit(c3);
    System.out.println("Done");
    
    executor.shutdown();
  }
}

Kết quả:

result: 1 + 2 = 3
3
Done
result: 1 + 3 = 4
result: 2 + 3 = 5

Khi bạn gọi f1.get() thì nó sẽ block thread chính lại để khi nào đối tượng c1 thực hiện xong và trả về kết quả.

Trường hợp đối tượng c1 mất quá nhiều thời gian để tính tổng  2 số thì cả chương trình sẽ bị delay rất lâu. Giải pháp cho trường hợp này là sử dụng method get() với thời gian timeout:

Ví dụ nếu sau 1 giây mà chưa có kết quả thì không chờ nữa: f1.get(1, TimeUnit.SECONDS)

Một số hạn chế của Future

Nếu muốn xử lý các vấn đề trên ta lại phải dùng while hoặc tạo 1 thread riêng và sử dụng method f1.isDone() để check khi nào future hoàn thành…

Từ Java 8 ta có thêm CompleteFuture để khắc phục những hạn chế bên trên. (Mình sẽ làm ví dụ CompleteFuture trong bài sau)

 

Okay, Done!

Download code ví dụ trên tại đây.

 

References:

https://dzone.com/articles/java-callable-future-understanding