Khi phát triển một ứng dụng đa luồng, chúng ta thường phải xử lý việc tổ chức công việc của các luồng. Ứng dụng của chúng ta càng lớn và chúng ta càng cần nhiều luồng cho các tác vụ đa luồng thì càng nhiềucó thể chạy đượccác đối tượng chúng ta tạo ra.

Cần lưu ý ở đây rằng việc tạo một luồng trong Java là một hoạt động khá tốn kém. Nếu chúng ta tạo một phiên bản mới của luồng mỗi lần để thực hiện một thao tác, chúng ta sẽ gặp vấn đề lớn về hiệu suất và kết quả là với tình trạng của ứng dụng.

Nhóm luồngThreadPoolExecutor sẽ hỗ trợ chúng tôi tại đây.

Nhóm luồng là một tập hợp các luồng được khởi tạo trước. Kích thước của nó có thể được cố định hoặc thay đổi.

Nếu có nhiều nhiệm vụ hơn luồng, thì các nhiệm vụ sẽ đợi trong hàng đợi nhiệm vụ. Chuỗi thứ N trong nhóm nhận một nhiệm vụ từ hàng đợi và sau khi thực hiện xong, chuỗi đó sẽ nhận một nhiệm vụ mới từ hàng đợi. Khi tất cả các tác vụ trong hàng đợi được thực thi, các luồng vẫn hoạt động và chờ các tác vụ mới. Khi các tác vụ mới xuất hiện, các luồng cũng bắt đầu thực hiện chúng.

ThreadPoolExecutor

Bắt đầu với Java 5, khung Executor đã đạt được giải pháp đa luồng. Nói chung, nó có rất nhiều thành phần và mục đích của nó là giúp chúng ta quản lý hiệu quả queue và thread pool.

Các giao diện chính là ExecutorExecutorService .

Executor là một giao diện với một phương thức thực thi void (Runnable runnable) duy nhất.

Khi chuyển một tác vụ sang triển khai phương thức này, hãy biết rằng nó sẽ được thực thi không đồng bộ trong tương lai.

ExecutorService — Một giao diện mở rộng giao diện Executor , thêm các khả năng để thực thi các tác vụ. Nó cũng có các phương thức để làm gián đoạn một tác vụ đang chạy và kết thúc nhóm luồng.

ThreadPoolExecutor triển khai các giao diện Executor ExecutorService và tách việc tạo tác vụ khỏi thực thi tác vụ. Chúng ta cần triển khai các đối tượng Runnable và gửi chúng cho người thực thi. ThreadPoolExecutorsau đó chịu trách nhiệm thực thi các tác vụ, tạo và làm việc với các luồng .

Sau khi một tác vụ được gửi để thực thi, một chuỗi hiện có trong nhóm sẽ được sử dụng. Điều này cải thiện hiệu suất. Nó giải quyết vấn đề lãng phí tài nguyên khi tạo và khởi tạo một luồng mới, sau đó lại giải quyết vấn đề thu gom rác sau khi chúng ta hoàn thành luồng.

ThreadPoolExecutor có 4 hàm tạo:


ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime, 
TimeUnit unit, 
BlockingQueue<Runnable> workQueue)
    

ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
    

ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime, 
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
    

ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime, 
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory, 
RejectedExecutionHandler handler)
    

Hàm tạo ThreadPoolExecutor có các tham số sau:

lõiPoolSize Tham số này cho biết có bao nhiêu luồng sẽ sẵn sàng (bắt đầu) khi dịch vụ thực thi bắt đầu.
kích thước hồ bơi tối đa Số luồng tối đa mà một dịch vụ thực thi có thể tạo.
giữ AliveTime Thời gian mà một luồng được giải phóng sẽ tiếp tục tồn tại trước khi bị hủy nếu số lượng luồng lớn hơnlõiPoolSize. Các đơn vị thời gian được chỉ định trong tham số tiếp theo.
đơn vị Đơn vị thời gian (giờ, phút, giây, mili giây, v.v.).
hàng đợi công việc Thực hiện một hàng đợi cho các nhiệm vụ.
xử lý Trình xử lý cho các tác vụ không thể hoàn thành.
chủ đềFactory Một đối tượng tạo chủ đề mới theo yêu cầu. Việc sử dụng các nhà máy luồng làm cho các cuộc gọi đến phần cứng luồng mới trở nên độc lập, cho phép các ứng dụng sử dụng các lớp con luồng đặc biệt, mức độ ưu tiên, v.v.

Tạo một ThreadPoolExecutor

Lớp tiện ích Executor có thể đơn giản hóa việc tạo ThreadPoolExecutor . Các phương thức của lớp tiện ích này giúp chúng ta chuẩn bị mộtThreadPoolExecutorsự vật.

newFixedThreadPool — Tạo một nhóm luồng sử dụng lại một số luồng cố định để thực thi bất kỳ số lượng tác vụ nào.

ExecutorService executor = Executors.newFixedThreadPool(10);
                    
newWorkStealingPool — Tạo nhóm luồng trong đó số luồng bằng với số lõi bộ xử lý có sẵn cho JVM. Mức đồng thời mặc định là một. Điều này có nghĩa là càng nhiều luồng sẽ được tạo trong nhóm thì càng có nhiều lõi CPU dành cho JVM. Nếu mức đồng thời là 4, thì giá trị đã truyền sẽ được sử dụng thay cho số lượng lõi.

ExecutorService executor = Executors.newWorkStealingPool(4);
                    
newSingleThreadExecutor — Tạo một nhóm với một luồng duy nhất để thực thi tất cả các tác vụ.

ExecutorService executor = Executors.newSingleThreadExecutor();
                    
newCachedThreadPool — Tạo một nhóm luồng để tạo các luồng mới khi cần, nhưng sử dụng lại các luồng đã tạo trước đó khi chúng khả dụng.

ExecutorService executor = Executors.newCachedThreadPool();
                    
newScheduledThreadPool — Tạo một nhóm luồng có thể lên lịch các lệnh để thực thi sau một khoảng thời gian trễ nhất định hoặc theo định kỳ.

ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
                    

Chúng ta sẽ xem xét từng loại hồ bơi trong các bài học sau.