Bài viết này sẽ cung cấp cho bạn các tính năng trong lập trình đa luồng multithread mà Java cung cấp cho lập trình viên. Hiểu được cách tạo, thi hành, và đồng bộ hóa nhiều luồng (thread) trong chương trình. Qua bài viết này bạn sẽ có khả năng phát triển được ứng dụng đa luồng với JAVA.

Multithread là gì?

Đa phần các chương trình bạn viết chỉ thực hành trong một luồng. Mổi chương trình xử lý một cách tuần tự những chỉ thị nối tiếp nhau cho đến khi hoàn tất xử lý và kết thúc chương trình.

Lập trình đa luồng Multiprogramming

Lập trình đa luồng Multiprogramming

Những chương trình đa luồng tương tự chường trình chỉ có một luồng mà bạn đã từng nghiên cứu trước đây. Chúng chỉ khác ở chỗ hỗ trợ đồng thời nhiều hơn một luồng, nghĩa là chúng có thể thi hành một cách đồng thời nhiều chỉ thị tuần tự. Mỗi chỉ thị tuần tự chỉ có duy nhất một dòng điều khiển độc lập với tất cả các dòng điều khiển khác. Những dòng điều khiển thi hành chỉ thị tuần tự độc lập gọi là luồng (thread).

Nếu máy tính bạn chỉ có 1 vi xử lý (CPU), bạn có thắc mắc là làm sao chương trình có thể thi hành nhiều luồng cùng lúc. Đối với hệ thống chỉ có một bộ xử lý, thì mội lúc chỉ có duy nhất một luồng thi hành. CPU sẽ nhanh chóng chuyển đổi giữa các luồng tạo ảo giác là các luồng được thi hành cùng lúc. Hệ thống một bộ xử lý hỗ trợ tính đồng thời luận lý (logic concurrency), chứ không phải tính đồng thời vật lý (physical concurrency). Tính đồng thời luận lý là một đặc tính được đưa ra khi nhiều luồng thi hành với những dòng điều khiển độc lập và riêng rẽ. Trong hệ thống nhiều bộ xử lý, thực tế là nhiều luồng thi hành cùng một lúc, đạt được tính đồng thời về mặt vật lý. Đặc tính quan trọng của những chương trình đa luồng là chúng hỗ trợ tính đồng thời luận lý, dù có hay không tính đồng thời vật lý.

Nhiều ngôn ngữ lập trình đã hỗ trợ tính đa chương (multiprogramming). Đa chương là quá trình thi hành đồng thời nhiều chương trình một các luận lý. Ví dụ chường trình có thể yêu cầu hệ điều hành thực hiện những chương trình A, B, C bằng cách sinh ra những tiến trình (process) cho mỗi chương trình. Những chương trình này có thể chạy song song, tùy thuộc vào các đặc tính đa chương được hỗ trợ bởi hệ điều hành bên dưới. Đa luồng kahc1 với đa chương ở chổ đa luồng cung cấp tính đồng thời trong ngữ cảnh của một tiến trình trong khi đa chương cung cấp tình đồng thời giữa các tiến tình. Luồng không phải là tiến trình (process). Chúng chỉ là những dòng điều khiển riêng rẽ xuất hiện bên trong một tiến trình (process).

Một chương trình đang thi hành phối hợp với một tiến trình. Ưu điểm của đa luồng là tính đồng thời của nó có thể được sử dụng trong một tiến trình nhằm cung cấp nhiều dịch vụ đồng thời cho người dùng. Đa luồng cũng yêu cầu chi phí xử lý ít hơn đa chương bời vì các luồng có thể đồng thời chia sẽ các tài nguyên dùng chung dễ dàng hơn.

Cách chức hỗ trợ đa luồng của JAVA.

Java có những hỗ trợ rộng rãi cho đa luồng và đa chương. JAVA hỗ trợ đa luồng xoay quanh lớp java.lang.Thread. Lớp Thread cung cấp khả năng tại ra nhựng đối tượng của lớp Thread với những dòng điều khiển riêng. Lớp Thread đóng gói dữ liệu và phương thức liên quan với những luồng thực hiện riêng rẽ và cho phép đa luồng được tích hợp bên trong khung hướng đối tượng.

Java cung cấp hai giải pháp đa luồng. Ở giải pháp thứ nhất, bạn tạo ra một lớp con của lớp Thread và tạo ra phương thức ghi đè (overrride) phương run để tạo ngõ vào và thi hành luồng. Khi tạo một thực thể (instance) của lớp con Thread, bạn gọi phương thức  start() của nó để thực hiện luồng (thread) như những chỉ thị tuần tự độc lập. Phương thức start() thừa kế từ lớp Thread. Nó khởi tạo đối tượng Thread bằng cách dùng khả năng đa luồng của hệ điều hành và gọi phương thức run().

Giải pháp tạo luồng phía trên rất đơn giản và dễ hiểu. Tuy nhiên có một trở ngại là nó yêu cầu những đối tượng Thread của bạn phài ở cấp dưới của lớp Thread trong cây thứ bậc lớp. Trong một vài trường hợp như trong các chương trình applet hoặc android yêu cầu trên có thể sẽ bị giới hạn đôi chút.

Tạo đa luồng Threading

Tạo đa luồng Threading

Giải pháp khác của Java khi tạo luồng thường không giới hạn vị trí của những đối tượng Thread trong cây thứ bậc lớp của bạn. ở giải pháp này, lớp của bạn thi công giao diện java.lang.Runable. Giao diện Runable chứa một phương thức run() và phải được tràn lên bởi lớp của của bạn. Để thi hành đối tượng của lớp dưới dạng luồng độc lập, bạn sẽ nghiên cứu cách tạo luồng bằng phương pháp này qua bài viết “Thi công giao diện Runable“.

Trạng thái của luồng Lifecycle of Java.

Luồng chuyển biến qua vài trạng thái từ khi chúng được tạo ra cho đến khi chúng “chết” đi. Tạo luồng (thread) bằng cách tao một đối tượng của lớp Thread hoặc những lớp con của chúng. Khi luồng được tạo lần đầu tiên, nó không tồn tại như một tập hợp các chỉ thị thi hành độc lập. Thay vào đó, nó là một khuôn mẫu (template) để từ đó một luồng đang thi hành sẽ được tạo ra. Trước tiên nó thi hành như một luồng khi được khởi động bằng cách dùng phương thức start() và thi hành thông qua phương thức run() . Trước khi khởi động một luồng, nó ở trong trang thái có thể thi hành (runnable). Khi một lớp đang ở trang thái có thể thi hành (runnable), nó có thể đang thi hành hoặc đợi chia sẽ bộ xử lý với những luồng khác. Một luồng có thể thi hành bước vào trạng thái đợi (wait) khi có một trong những phương thức của nó được gọi khiến cho nó chuyển sang trang thái không thể thi hành (not runnable). Trong trạng thái không thể thi hành (not runnable), một luồng không thể đợi để chia sẽ bộ xử lý, nhưng luồng đó sẽ đợi một biến cố xảy ra để chuyên sang trang thái có thể thi hành (runnable).

Phương thức sleep() là một ví dụ cho vấn đề được bàn phía trên. Phương thức sleep()  làm cho một luông bước vào trạng thái không thể thi hành (not runnable) cho đến khi thời gian chỉ định trôi qua. Một luồng cũng có thể bước vào trang thái không thể thi hành (not runnable) khi nó đang đợi các thiêt bị I/O hoàn thành hoặc đợi thi hành xong lời gọi phương thức khác.

Ghi chú: không có sư liện quan nào giữa trang thái có thể thi hành (runnable) của một luồng với giao diện có thể thi hành Runnable.

Một luồng bước ra khỏi trang thái không thể thi hành (not runnable) và trở về trang thái có thể thi hành (runnable) khi một biến cố mà nó đang đợi xảy ra. Ví dụ, một luồng đang “ngủ” phải đợi thời gian ngủ chỉ định xuất hiện. Một luồng đang đợi I/O thì phải đợi cho đến khi hoạt động I/O chấm dứt.

Một luồng có thể chuyển trang thái từ luồng mới (new thread) sang có thể thi hành, sang trạng thái luồng không thể thi hành sang trang thái luồng “chết” khi phương thức stop() của luồng được gọi hoặc khi luồng đạ thực hiện xong tác vụ. Khi một luồng bước vào trang thái chết, nó bị bỏ đi. Nó không thể “sống lại” hoặc trở lại bất kỳ trạng thái nào.

About the author

Kevin Dang

Hey there! My name is Kevin Dang, I am website, software, mobile app develop, web admin system. Expert living in Hồ Chí Minh (Việt Nam). I am very interested in digital marketing with: SEO, Facebook, Google Ads ... This blog is where I will share the experiences, techniques and knowledge I have learned.