Chủ đề, Nhóm chủ đề, Thông báo chủ đề trong Java

Tram Ho

Giới thiệu

Trong bài viết này chúng ta cùng tìm hiểu về Thread, Multi Thread, Daemon Thread, Deadlock, Life Cycle…. hiểu và vận dụng thread vô thực tế. GetGoooo…..

  • Nội dung của bài viết được hỗ trợ 1 phần bởi ChatGPT

Định nghĩa

Thread là một thuộc tính duy nhất của Java. Nó là đơn vị nhỏ nhất của đoạn mã có thể thi hành được mà thực hiện một công việc riêng biệt. Ngôn ngữ Java và máy ảo Java cả hai là các hệ thống đươc phân luồng.

Multi Thread

  • Java hổ trợ đa luồng, mà có khả năng làm việc với nhiều luồng. Một ứng dụng có thể bao hàm nhiều luồng
  • Đa luồng giữ thời gian nhàn rỗi của hệ thống thành nhỏ nhất( tức vắt kiệt luôn =))). Điều này cho phép bạn viết các chương trình có hiệu quả cao với sự tận dụng CPU là tối đa. Mỗi phần của chương trình được gọi một luồng, mỗi luồng định nghĩa một đường dẫn khác nhau của sự thực hiện. Đây là một thiết kế chuyên dùng của sự đa nhiệm.
  • Trong sự đa nhiệm, nhiều chương chương trình chạy đồng thời, mỗi chương trình có ít nhất một luồng trong nó. Một vi xử lý thực thi tất cả các chương trình. Cho dù nó có thể xuất hiện mà các chương trình đã được thực thi đồng thời, trên thực tế bộ vi xử lý nhảy qua lại giữa các tiến trình.

Lý thuyết sẽ là như thế, mình cùng vô thực hành để hiểu hơn về Thread nhen!

Tạo và quản lý Thread

Khi các chương trình Java được thực thi, luồng(Thread) chính luôn luôn đang được thực hiện, nó được tạo ra một cách tự động khi bạn start chương trình, các luồng con thường sẽ được tạo thông qua nó, nó cũng là luồng kết thuốc cuối cùng của chương trình

để tạo ra Thread, thường sẽ có 2 cách

  1. Sử dụng Thread

2.Sử dụng Runnable

Có 1 vài sự khác biệt khi bạn sử dụng Runnable và Thread

  1. Runnable là một interface trong Java, còn Thread là một class implement từ Runnable. Nếu muốn tạo một luồng mới, bạn có thể implement interface Runnable hoặc kế thừa từ class Thread.
  2. Runnable chỉ cung cấp một phương thức run() để chạy một tác vụ, trong khi Thread cung cấp nhiều phương thức khác để điều khiển luồng, chẳng hạn như start(), interrupt(), join() và sleep().
  3. Runnable có thể được sử dụng trong nhiều trường hợp, trong khi Thread chỉ có thể sử dụng trong một số trường hợp cụ thể. Do đó, sử dụng Runnable là một lựa chọn tốt hơn trong trường hợp muốn chạy nhiều luồng với cùng một tác vụ.

Ok giờ cùng thực thực hiện 1 chương trình và phân tích về nó

image.png

Trích xuất từ kết quả
image.png

Mỗi luồng trong chương trình Java được đăng ký cho một quyền ưu tiên. Máy ảo Java không bao giờ thay đổi quyền ưu tiên của luồng. Quyền ưu tiên vẫn còn là hằng số cho đến khi luồng bị ngắt.

Mỗi luồng có một giá trị ưu tiên nằm trong khoảng từ Thread.MIN_PRIORITY đến Thread.MAX_PRIORITY tức 1-10. Mỗi luồng phụ thuộc vào một nhóm luồng, và mỗi nhóm luồng có quyền ưu tiên riêng thường thì bằng 5.

image.png
Lượn lờ trên mạng thì mình tìm được chiếc hình cũ kỹ này thể hiện được vòng đời của Thread.

Trạng thái của Thread

1 Thread trong Java thường tồn tại 6 trạng thái

New: Thread đã được tạo nhưng chưa được chạy.

Runnable: Thread đang chạy hoặc đang chờ CPU để được thực thi.

Blocked: Thread bị chặn khi đang chờ một đối tượng được sử dụng bởi một thread khác.

Waiting: Thread đang chờ một sự kiện xảy ra hoặc một thread khác gửi một thông báo cho nó.

Timed waiting: Thread đang chờ một số thời gian nhất định.

Terminated: Thread đã kết thúc hoặc bị tắt bất cẩn.

Một luồng khi được tạo ra sẽ không tự động chạy mà cần được được gọi qua phương thức start().

Khi phương thức sleep() được gọi, nó sẽ được tạm ngưng và quay về trạng thái Waiting

Một số hàm thông dụng của Thread.

getName() lấy tên Thread.

isAlive() trả về True nếu Thread còn tồn tại.

getPriority() trả về điểm ưu tiên của Thread.

setName() set tên cho Thread.

join() hàm này sẽ chờ cho đến khi Thread của bạn chết.

isDaemon() có phải Thread Daemon(Luồng Hiếm) hay không.

resume() đánh dấu luồng là luồng hiếm(Daemon).

sleep() tạm ngưng thực thi.

start() Gọi phương thức run() để bắt đầu một luồng.

Luồng hiếm (Daemon Thread)

Daemon Thread hay còn có cái tên thân thiện hơn và luồng hiếm được chỉ định như là luồng “background” (nền). Người sử dụng tạo ra các luồng người sử dụng và cung cấp các “dịch vụ” cho luồng khác.

Trong Java thì luôn có ít nhất 1 luồng hiếm tồn tại nó được biết đến như là luồng “garbage collection” (thu lượm những dữ liệu vô nghĩa – dọn rác)

Bạn có thể dùng phương thức setDaemon để chỉ định 1 Thread là Thead hiếm.

Ví dụ Thread Notify, Thread Pool đơn giản

Chúng ta cùng làm một ví dụ đơn giản về Thread nha.

Trong ví dụ này chúng ta sẽ tạo ra 1 Thread Pool, và khi Thread hoàn thành chúng ta sẽ bắn notify để thông báo.

Ok! bắt đầu thôi….

Để Thread có thể đăng ký các Listener, mình sẽ tạo ra một Thread mới implements từ Runnable

Tạo interface ThreadCompleteListener để các Listener implements lại.

Tạo một class để quản lý Thread

  • VoidSupplier thì cũng là một FunctionalInterface tương từ Supplier thôi nhé.

Ok giờ mình cùng test thôi.

trong đó ClassRunThread là class chúng đa muốn chạy trong Thread mới, ClassReceiveNotify được implements ThreadCompleteListener để nhận thông báo.

Screenshot 2023-02-05 at 21.37.29.png

và đây là kết quả chúng ta nhận được.

Nâng cao hơn 1 tí nào, chúng ta cùng tạo thêm cho nó cái Pool để quản lý lượng Thread được tạo ra nha.

Trong class phía trên mình sẽ lưu số lượng Thread đang chạy trong currentThread, mình coi ThreadPool như là một Listener để nhận được thông báo khi Thread hoàn thành và điều chỉnh currentThread lại.

Trong ví dụ trên, mình dùng hàm sleep để tạm ngưng 100ms khi currentThread > maxThread. (sẽ có thêm nhiều cách khác để bạn làm, ví dụ như đưa vào Queue…. trong ví dụ đơn này này mình sleep cho lẹ nhé =)) )

Ok! tiếp theo mình tạo thêm một cái Builder nữa cho nó chuyên nghiệp nha

Giờ mình cùng xem thành quả nha.

Mình tạo ThreadPool với số max là 2, nhưng mình chạy cùng lúc 4 Thread và hình dưới là kết quả

Screenshot 2023-02-05 at 21.55.09.png

như các bạn đã thấy process 1process 2 được xử lý cùng lúc, trong khi process 3process 4 thì cần phải chờ vì Pool size chỉ cho phép 2.

Kết luận

Trong bài viết này mình đã đi qua lý thuyết về Thread, làm ví dụ đơn giản về Thread được mình chích ra từ các dự án thực tế và làm đơn giản lại để các bạn dễ hiểu.

Cảm ơn các bạn đã xem bài, nếu có sai xót gì trong content, mình mong nhận được ý kiến đóng góp từ mọi người

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo