concurrent - kết quả bóng đá hôm nay
Pool luồng đóng một vai trò rất quan trọng trong hệ thống Tomcat. Dưới đây chúng ta sẽ tìm hiểu ngắn gọn về cách mà pool luồng hoạt động trong Tomcat, đặc biệt là trong quá trình khởi động container.
Trong quá trình khởi động container, phương thức org.apache.catalina.core.ContainerBase#initInternal được gọi:
1@Override
2protected void initInternal() throws LifecycleException {
3 reconfigureStartStopExecutor(getStartStopThreads());
4 super.initInternal();
5}
Phương thức này trước tiên sẽ lấy số lượng luồng cần thiết từ hàm getStartStopThreads, cụ thể như sau:
1@Override
2public int getStartStopThreads() {
3 return startStopThreads;
4}
Mặc định, giá trị của biến startStopThreads
trong lớp ContainerBase được cài đặt là 1:
1private int startStopThreads = 1;
Sau khi xác định số luồng cần sử dụng, nó sẽ tiến hành cấu hình pool luồng thông qua phương thức reconfigureStartStopExecutor:
1private void reconfigureStartStopExecutor(int threads) {
2 if (threads == 1) {
3 // Sử dụng executor giả
4 if (!(startStopExecutor instanceof InlineExecutorService)) {
5 startStopExecutor = new InlineExecutorService();
6 }
7 } else {
8 // Giao việc thực thi cho Service
9 Server server = Container.getService(this).getServer();
10 server.setUtilityThreads(threads);
11 startStopExecutor = server.getUtilityExecutor();
12 }
13}
Nếu pool luồng hiện tại là null, nó sẽ chuyển sang nhánh đầu tiên và tạo ra một đối tượng InlineExecutorService mới.
Toàn bộ quá trình trên diễn ra trong lúc khởi tạo đối tượng StandardEngine, tức là trong phương thức initInternal. Sau đó, pool luồng sẽ được sử dụng trong phương thức startInternal, nơi các thành phần con của StandardEngine sẽ được gửi đến để xử lý:
1// Khởi động các thành phần con nếu có
2Container[] children = findChildren();
3List<Future<Void>> results = new ArrayList<>();
4for (Container child : children) {
5 results.add(startStopExecutor.submit(new StartChild(child)));
6}
Đối tượng StartChild ở đây khá đơn giản, chỉ đơn thuần là gọi phương thức start của thành phần con tương ứng:
1private static class StartChild implements Callable<Void> {
2 private Container child;
3
4 public StartChild(Container child) {
5 this.child [cwin666](/) = child;
6 }
7
8 @Override
9 public Void call() throws LifecycleException {
10 child.start();
11 return null;
12 }
13}
Về phía InlineExecutorService, kế thừa từ lớp cha java.util.concurrent.AbstractExecutorService, nó sẽ gói callable thành FutureTask trước khi thực thi:
1public <T> Future<T> submit(Callable<T> task) {
2 if (task == null) throw new NullPointerException();
3 RunnableFuture<T> ftask = newTaskFor(task);
4 execute(ftask);
5 return ftask;
6}
7
8protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
9 return new FutureTask<T>(callable);
10}
Tiếp theo là quá trình thực thi:
1@Override
2public void execute(Runnable command) {
3 synchronized (lock) {
4 if (shutdown) {
5 throw new RejectedExecutionException();
6 }
7 taskRunning = true;
8 }
9 command.run();
10 synchronized (lock) {
11 taskRunning = false;
12 if (shutdown) {
13 terminated = true;
14 lock.notifyAll();
15 }
16 }
17}
Như vậy, vai trò chính của startStopExecutor là giúp keo da banh khởi động các thành phần con của container, cụ thể hơn là host. Lưu ý rằng lớp Host cũng kế thừa từ ContainerBase, vì vậy cơ chế hoạt động của nó cũng tương tự như đã mô tả ở trên. Chúng ta sẽ tiếp tục tìm hiểu chi tiết hơn trong các bài viết tiếp theo.