Trước khi bắt đầu mon men vào câu hỏi chính của chúng ta ngày hôm nay, tốt nhất ta nên dạo đầu 15 phút để cảm hướng nó tuôn trào một xí chứ nhỉ. Rồi rồi, hãy cho tôi xem các ngón tay linh hoạt của các bạn nàooo.

A. Tổng quan về Thread
    1. Thread Trong Java Là Gì?

Thread (luồng) về cơ bản là một tiến trình con (sub-process). Một đơn vị xử lý nhỏ nhất của máy tính có thể thực hiện một công việc riêng biệt. Trong Java, các luồng được quản lý bởi máy ảo Java (JVM).

Multi-thread (đa luồng) là một tiến trình thực hiện nhiều luồng đồng thời. Một ứng dụng Java ngoài luồng chính có thể có các luồng khác thực thi đồng thời làm ứng dụng chạy nhanh và hiệu quả hơn.

Vòng đời của Thread
  • New : Đây là trạng thái khi luồng vừa được khởi tạo bằng phương thức khởi tạo của lớp Thread nhưng chưa được start(). Ở trạng thái này, luồng được tạo ra nhưng chưa được cấp phát tài nguyên và cũng chưa chạy. Nếu luồng đang ở trạng thái này mà ta gọi các phương thức ép buộc stopresumesuspend … sẽ là nguyên nhân xảy ra ngoại lệ IllegalThreadStateException .
  • Runnable : Sau khi gọi phương thức start() thì luồng test đã được cấp phát tài nguyên và các lịch điều phối CPU cho luồng test cũng bắt đầu có hiệu lực. Ở đây, chúng ta dùng trạng thái là Runnable chứ không phải Running, vì luồng không thực sự luôn chạy mà tùy vào hệ thống mà có sự điều phối CPU khác nhau.
  • Waiting: Thread chờ không giới hạn cho đến khi một luồng khác đánh thức nó.
  • Deadthread vào trạng thái này khi thi hành xong tác vụ.

 2. Ưu Nhược Điểm Của Nó?

  • Nhược điểm:
    • Càng nhiều luồng thì xử lý càng phức tạp.
    • Xử lý vấn đề về tranh chấp bộ nhớ, đồng bộ dữ liệu khá phức tạp.
    • Cần phát hiện tránh các luồng chết (dead lock), luồng chạy mà không làm gì trong ứng dụng cả.
  • Ưu điểm:
    • Nó không chặn người sử dụng vì các luồng là độc lập và bạn có thể thực hiện nhiều công việc cùng một lúc.
    • Mỗi luồng có thể dùng chung và chia sẻ nguồn tài nguyên trong quá trình chạy, nhưng có thể thực hiện một cách độc lập.
    • Luồng là độc lập vì vậy nó không ảnh hưởng đến luồng khác nếu ngoại lệ xảy ra trong một luồng duy nhất.
    • Có thể thực hiện nhiều hoạt động với nhau để tiết kiệm thời gian. Ví dụ một ứng dụng có thể được tách thành : luồng chính chạy giao diện người dùng và các luồng phụ nhiệm gửi kết quả xử lý đến luồng chính.

 3. Ví dụ

Có 2 cách để tạo ra 1 thread, đó là kế thừa lớp Thread và tạo lớp thread từ giao diện Runnable.

  • Kế thừa từ Thread class.

  • Tường minh từ Runnable interface

Như chúng ta có thể thấy, chúng ta cần phải nạp chồng hoặc triển khai mã trong phương thức run(), và sau khi khởi tạo đối tượng, ta sẽ gọi start() để chạy nó.

Điểm Gờ cần sờ:

  • Phương thức Thread.sleep() cho phép bạn dừng thread lại trong một khoảng thời gian.
  • Khi nào implements từ interface Runnable?
    • Cách hay được sử dụng và được yêu thích là dùng interface Runnable, bởi vì nó không yêu cầu phải tạo một lớp kế thừa từ lớp Thread.

Sử dụng Interface Runnable có một cái lợi là giúp ta kế thừa từ 1 lớp khác ngoài lớp thread, vì nếu sử dụng Subclass thì chỉ có thể thừa kế một lớp Thread vì java không hỗ trợ đa thừa kế.

Ngoài ra, Thread Pool rất hiệu quả và có thể được cài đặt, sử dụng rất hơn giản.

    • Trong trường hợp còn lại ta có thể kế thừa từ lớp Thread.
  • Mỗi Thread có một mức ưu tiên (priority) (Thread.setPriority). Ưu tiên được đại diện bởi một số từ 1 đến 10. Trong hầu hết các trường hợp, lịch trình của thread được sắp xếp theo thứ tự ưu tiên của chúng (được gọi là lập kế hoạch ưu tiên). Nhưng nó không được bảo đảm bởi vì nó phụ thuộc vào thông số kỹ thuật của JVM.

B. Thread#sleep trong Java

Thread#sleep() được sử dụng để tạm ngưng quá trình của thread hiện tại với một khoảng thời gian được chỉ định. Lưu ý khoảng thời gian tạm ngưng không thể là số âm nếu không sẽ bị ném IllegalArgumentException.

Chúng ta có các overloading sleep() sau:

  • Thread.sleep(long millis) – Tạm ngưng thread hiện tại khoảng millis.
  • Thread.sleep(long milis, long nanos) – Tạm ngưng thread hiện tại khoảng millis và thêm một khoảng nanos từ 0 đến 999999

Thread sleep hoạt động như thế nào?

  • Thread.sleep() sẽ nói chuyện với bộ lập lịch của hệ thống để đẩy thread hiện tại và trạng thái chờ với một khoảng thời gian được chỉ định. Khi khoảng thời gian chờ thread sẽ chuyển từ trạng thái chờ sang trạng tháy runnable và chờ đến khi CPU thực thi tiếp thread.
  • Thread sleep sẽ không làm ảnh hưởng đến thread hiện tại mà chỉ đơn giản là tạm ngưng thực thi một khoảng thời gian, các cơ chế đồng bộ, các kết quả tính toán sẽ không bị ảnh hưởng.

Một vài ví dụ:

Thread.sleep là một cách hiệu quả để cung cấp thời gian xử lý cho các luồng khác của một ứng dụng hoặc các ứng dụng khác mà có thể chạy trên hệ thống máy tính nhưng Tại sao chúng ta lại phải tránh sử dụng Thread.Sleep?

Sẽ có một số vấn đề khiến chúng ta cần phải biết có nên dùng Thread.sleep hay không, có nghĩa là không phải bỏ nó hoàn toàn:

  • Nó có thể làm cho bạn phải chờ khi bạn cần kiểm tra nhanh một chức năng nào đó. Hoặc khi hệ thống đã sẵn sàng rồi, nhưng vẫn phải chờ cho hết thời gian thì mới có thể thực hiện tiếp được, gấy ức chế cực mạnh.
  • Bạn không thể biết chính xác mình sẽ phải chờ trong bao lâu. Ví dụ, Thread.sleep(20000) thì theo lý thuyết luồng này sẽ chờ 20 giây rồi sẽ tiếp tục thực hiện tiếp những chức năng đằng sau nó. Nhưng, khoảng thời gian chờ thật sự sẽ phụ thuộc vào bộ lập lịch và bộ hẹn giờ của hệ thống. Nếu hệ thống đang rảnh thì khoảng thời gian chờ có thể gần với khoảng thời gian mà chúng ta chỉ định, còn nếu hệ thống đang bận thì khoảng chênh lệch sẽ khá lớn so với khoảng thời gian được chỉ định.
  • Một thread đang ngủ có thể bị làm gián đoạn bởi các thread khác đang chạy, lúc này thread đang ngủ sẽ thức dậy và ném InterruptedException, cho nên chúng ta phải xử lý exception cho sleep().
  • Tại vì thời gian chờ và tiếp tục tiến trình không phải do dev có thể kiểm soát được, nên trong 1 số trường hợp hi hữa, hệ thông có thể không hoạt động chính xác. Ví dụ như phải thực thi 1 công việc gì đó trước khi close nhưng vì sai số vài milisecond mà tác vụ đó đã không kịp thực hiện, dẫn đến thiếu dữ liệu.

Tuy nhiên chúng ta vẫn có thể sử dụng Thread.sleep khi cung cấp thời gian cho các luồng chạy ngầm khác, hoặc một số trường hợp khác.

Đuối, cuối cùng cũng ra rồi, lâu rồi mới làm lại chuyện này nên mất sức quá. Anh em thông cảm nhé. Nice day ae.

Cảm ơn các bạn đã đọc hết bài viết, theo dõi SuSuDev để cập nhật các bài viết mới và thú vị nhé!

Nếu các bạn có bất kỳ thắc mắc hoặc góp ý xin vui lòng để lại bình luận bên dưới nhé!

Cảm ơn các bạn!

Nhớ ghi nguồn https://susudev.com khi đăng tải lại bài viết này