1 có bao nhiêu cách để tạo thread c năm 2024
Trong Java, chúng ta có 2 cách để khởi tạo và chạy một thread, đó là sử dụng class Thread hoặc là interface Runnable. Cụ thể như thế nào, trong bài viết này, chúng ta sẽ cùng nhau tìm hiểu về chúng các bạn nhé! Show Class ThreadCác bạn có thể dễ dàng tạo mới một thread bằng cách extend class của các bạn từ class Thread rồi sau đó override phương thức run() của class Thread này. Code bên trong run() method sẽ là tác vụ mà chúng ta cần execute trong thread mới. Ví dụ mình muốn tạo mới một thread để tính tổng của 2 số bằng cách extend class Thread thì mình sẽ tạo mới một class extend class Thread và override lại phương thức run() như sau: package com.huongdanjava.javaexample; public class Calculator extends Thread { @Override public void run() { int a = 2; int b = 7; int sum = a + b; System.out.println(sum); } } Để chạy thread trong trường hợp này, chúng ta sẽ tạo mới instance của class Calculator và gọi phương thức start() của đối tượng này để chạy các bạn nhé. Ví dụ: package com.huongdanjava.javaexample; public class Example { public static void main(String[] args) { Calculator calculator = new Calculator(); calculator.start(); } } Kết quả: Các bạn có thể thấy rõ việc code của chúng ta được execute trong main thread hay là một thread khác bằng cách add thêm một số dòng code như sau: package com.huongdanjava.javaexample; public class Calculator extends Thread { @Override public void run() { System.out.println("Calculator : " + Thread.currentThread().getName()); int a = 2; int b = 7; int sum = a + b; System.out.println(sum); } } package com.huongdanjava.javaexample; public class Example { public static void main(String[] args) { System.out.println("Main : " + Thread.currentThread().getName()); Calculator calculator = new Calculator(); calculator.start(); } } Kết quả: Nếu các bạn để ý thì sẽ có thắc mắc là nếu chúng ta gọi phương thức run() thay vì phương thức start() của class Calculator thì có sự khác biệt gì? Câu trả lời là nếu các bạn gọi phương thức run() thì code bên trong nó sẽ được execute trong cùng thread của chương trình thay vì một thread mới. Ví dụ nếu bây giờ mình đổi qua gọi phương thức run() trong hàm main của ứng dụng: package com.huongdanjava.javaexample; public class Example { public static void main(String[] args) { System.out.println("Main : " + Thread.currentThread().getName()); Calculator calculator = new Calculator(); calculator.run(); } } các bạn sẽ thấy kết quả như sau: Interface RunnableVới interface Runnable thì class của các bạn cần implement interface này và hiện thực phương thức run() được định nghĩa trong nó. Trong ví dụ trên, thay vì extend từ class Thread mình có thể implement interface Runnable như sau: package com.huongdanjava.javaexample; public class Calculator implements Runnable { public void run() { System.out.println("Calculator : " + Thread.currentThread().getName()); int a = 2; int b = 7; int sum = a + b; System.out.println(sum); } } Để tạo mới thread và chạy ứng dụng của chúng ta trong trường hợp này, các bạn cần tạo mới class Thread với tham số là class implement interface Runnable của chúng ta. Ví dụ như sau: package com.huongdanjava.javaexample; public class Example { public static void main(String[] args) { System.out.println("Main : " + Thread.currentThread().getName()); Thread thread = new Thread(new Calculator()); thread.start(); } } Kết quả cũng như vậy: Tổng kếtViệc sử dụng extend class Thread hay implement interface Runnable là tuỳ vào nhu cầu của các bạn nhưng mình prefer việc implement interfacve Runnable hơn vì trong Java, chúng ta có thể implement nhiều interface khác nhau nhưng chỉ có thể extend từ một class nào đó. Chào các bạn. Bài viết này ra đời trong bối cảnh có rất nhiều bạn quan tâm đến các bài viết về Thread và đồng bộ hóa của mình, bắt đầu từ Bài 41. Nếu các bạn có theo dõi các bài viết này, sẽ thấy mình đã bỏ hẳn một bài viết giúp tổng hợp các phương thức hữu ích của Thread. Thật ra nếu bỏ qua việc tìm hiểu các phương thức này, cũng không gây khó khăn cho việc chúng ta đi nhanh qua các bài học sau. Nhưng như vậy thì thật là tiếc vì bản thân Thread có nhiều phương thức khá hay, nếu lúc nào đó bỗng nhiên bạn cần đến, thì việc tìm hiểu thêm về chúng cũng mất kha khá thời gian. Và cũng nhân tiện có nhiều bạn cũng đặt các câu hỏi xoay quanh một vài phương thức được dùng nhiều, hôm nay mình viết hẳn một bài để tổng hợp lại các phương thức đó của Thread lại. Mình sẽ tập trung giải nghĩa cụ thể vào từng phương thức, có ví dụ rõ ràng, để các bạn nắm rõ hơn và để mình nhanh chóng cho ra những bài viết còn lại của chuỗi kiến thức Thread khá là đồ sộ này nhé. Lưu ý rằng bài viết hôm nay sẽ chưa có đủ mặt các phương thức, nhưng mình sẽ cập nhật thêm sau này và sẽ để lại đường link đến bài này từ các bài viết liên quan khác. Thread.sleep()Một phương thức đơn giản nhưng khá nhiều bạn thắc mắc. Giải Nghĩasleep() là một phương thức static của Thread. Do đó chúng ta gọi kèm với tên của lớp: Thread.sleep(). Thread.sleep() làm cho Thread hiện tại (chính là Thread đang gọi đến lệnh Thread.sleep()) phải tạm hoãn lại việc thực thi trong một khoảng thời gian được chỉ định. Nói cho đầy đủ thì là vậy, nhưng các lập trình viên hay dùng theo tên của phương thức, đó là “Ngủ”. Tuy Thread.sleep() được nạp chồng cho phép bạn chỉ định thời gian ngủ cho Thread hiện tại tính đến nano giây. Nhưng bạn đừng có nghĩ rằng Thread.sleep() sẽ thực sự ngủ với chính xác khoảng thời gian mà bạn định nghĩa nhé. Vì việc ngủ và thức này khiến cho hệ thống phải xử lý và cho ra các độ trễ khác nhau tùy vào thiết bị phần cứng nữa. Do đó Thread.sleep() cũng chỉ tương đối, và chúng ta không bao giờ được dùng Thread.sleep() để xây dựng một chức năng hẹn giờ hay đếm ngược thời gian, điều mà đòi hỏi tính chính xác về mặt thời gian rất cao. Sử DụngThread.sleep() được nạp chồng bởi 2 phương thức.
Khi sử dụng Thread.sleep(), bạn phải try catch phương thức này bằng một có tên là InterruptedException. Exception này sẽ được tung ra nếu như có một Thread nào đó khác interrupt Thread này (dừng Thread lại) khi Thread.sleep() đang hoạt động. Ví DụMột ví dụ đơn giản, ví dụ này sẽ tin ra console các con số từ 0 đến 5. Mỗi lần in cách nhau nửa giây (500 mili giây). Và vì chúng ta không start() bất cứ Thread nào trong đoạn code dưới, điều đó không có nghĩa rằng là hiện tại ứng dụng đang rỗng không có Thread nào đấy nhé. Bản thân phương thức main() tự nó đã được đưa vào một Thread rồi, gọi là main thread, nên bạn có thể thoải mái gọi đến Thread.sleep() ở đây. public static void main(String[] args) { }join()Giải NghĩaPhương thức join() cho phép một Thread phải chờ cho đến khi các Thread khác kết thúc. Vậy Thread nào phải chờ Thread nào? Vấn đề này khiến nhiều bạn bỡ ngỡ ban đầu, do chỉ có một phương thức join() thì thể hiện thế nào về việc Thread nào chờ Thread nào. Bạn chỉ cần nhớ, Thread nào sử dụng (hay khai báo) các Thread khác, mà một trong các Thread được khai báo này gọi đến phương thức join(), Thread sử dụng sẽ phải đợi Thread khai báo đó kết thúc mới làm tiếp công việc của mình. join() cũng có các phương thức nạp chồng cho phép Thread hiện tại chỉ cần phải chờ trong một khoảng thời gian tính bằng mili giây hoặc thêm đến nano giây. Và cũng như Thread.sleep(), join() không thực sự đếm thời gian chính xác, nên bạn cũng đừng dùng join() cho một số tình huống đòi hỏi mặt khắt khe về thời gian nhé. Sử Dụngjoin() được nạp chồng bởi 3 phương thức.
Cũng giống như Thread.sleep(), sử dụng join() cũng cần phải try catch với InterruptedException. Cả hai phương thức này sẽ tung ra Exception này khi được gọi bởi lệnh interrupt. Ví DụChúng ta hãy xây dựng một Thread đơn giản sau đây. Thread này khi chạy sẽ in ra các con số từ 0 đến 5 ở mỗi 0,5 giây. public class MyThread extends Thread { }Còn ở phương thức main() chúng ta sẽ khai báo 3 đối tượng Thread từ lớp MyThread này. Sau khi start thread1 xong thì gọi thread1.join(), sau đó chúng ta cũng sẽ start các Thread còn lại. public static void main(String[] args) { }Kết quả in ra console như sau. Thread1 0 Thread1 1 Thread1 2 Thread1 3 Thread1 4 Thread2 0 Thread3 0 Thread2 1 Thread3 1 Thread2 2 Thread3 2 Thread2 3 Thread3 3 Thread2 4 Thread3 4 Bạn có thể thấy, sau khi thread1.start(), thread1 này sẽ bắt đầu in các con số ra console. Tuy nhiên lời gọi thread1.join() sau đó khiến Thread đang sử dụng thread1 này (chính là main thread, thread đang chứa phương thức main() của chúng ta) rơi vào trạng thái đợi cho thread1 hoàn thành, trong quá trình đợi đó, các thread2 và thread3 khi này vẫn chưa được thực thi với hàm start(). Sau khi thread1 đếm xong và hoàn thành nhiệm vụ, các Thread còn lại mới được chạy và bắt đầu đếm là vậy. interrupt()/isInterrupted()/Thread.interrupted()Giải NghĩaĐôi khi chúng ta cần phải ngưng một Thread nào đó đang hoạt động. Cách hợp lý là gọi đến phương thức interrupt() của Thread. Lời gọi interrupt() thực chất cũng không làm cho Thread được gọi đến ngưng tác vụ ngay đâu, điều đó khá là nguy hiểm khi mà hệ thống không biết chắc Thread này đang làm việc gì, biết đâu nó đang ghi một file quan trọng nào đó. Việc một Thread khác interrupt() thoải mái một Thread nào đó có thể gây nên hậu quả khôn lường. Do đó, interrupt() không được xây dựng sẵn các lệnh giúp dừng Thread từ hệ thống, nó chỉ được xem như là một chỉ thị đưa ra cho Thread đang hoạt động biết, tốt hơn hết chính Thread đang hoạt động đó phải biết được chỉ thị này và tự biết cách ngưng tác cụ của mình lại. Một lát ở ví dụ bên dưới chúng ta sẽ nắm được điều này. Hai phương thức còn lại isInterrupted() và Thread.interrupted() dùng để kiểm tra Thread này có bị interrupt hay chưa. Sử Dụng
Ví DụVí dụ lần này chúng ta hãy đi từ phương thức main(), để xem với lời gọi interrupt() như thế này thì MyThread phải làm sao là đúng nhé. public static void main(String[] args) { }Nếu như ở MyThread, chúng ta “thờ ơ” với InterruptedException, tức là không có chuẩn bị gì cho sự interrupt cả, như sau. public class MyThread extends Thread { }Kết quả in ra console sẽ như sau. Bạn thấy ở phương thức main() gọi interrupt() trong “vô vọng”, vòng lặp vẫn lặp và đếm như thường, nó chỉ kết thúc khi hoàn thành tác vụ mà thôi. We start this Thread 0 1 We stop this Thread 2 3 4 Tuy nhiên, nếu chúng ta sửa MyThread một chút, có “trách nhiệm” hơn vớ InterruptedException, Thread này sẽ kết thúc dễ dàng do có sự chuẩn bị trước. public class MyThread extends Thread { }Console sẽ in ra như sau. We start this Thread 0 1 We stop this Thread OK, I'm stop. Hoặc try catch như thế này cũng cho ra kết quả viên mãn như trên. public class MyThread extends Thread { }Thread.currentThread()Giải NghĩaLời gọi Thread.currentThread() sẽ nhận về một tham chiếu đến đối tượng Thread hiện tại. Phương thức này cũng không quá phức tạp nên mình cũng không giải thích gì nhiều. Ví DụBạn hãy nhìn vào MyRunnable sau. Trong trường hợp này thì để có thể lấy được tên của Thread đang chạy, chỉ có cách gọi đến Thread.currentThread() mà thôi. public class MyThread extends Thread { }0 Phương thức main() như sau. public class MyThread extends Thread { }1 Kết quả in ra console. public class MyThread extends Thread { }2 getName()/setName()Giải NghĩaMặc định thì các Thread khi khởi chạy trong ứng dụng, sẽ được hệ thống đặt cho một cái tên, tuần tự, như sau: Thread-0, Thread-1,…. Nếu bạn thấy các tên này rất khó để gợi nhớ, hãy đặt cho chúng một cái tên khác theo ý bạn. Sử Dụng
Ví DụNhư bao ví dụ khác, chúng ta cần một Thread khá đơn giản như sau. Thread này sẽ in ra các con số từ 0 đến 5 ở mỗi 0,5 giây. Tuy nhiên Thread có kèm theo phương thức getName() để hiển thị tên của nó ra console. public class MyThread extends Thread { }3 Ở main() chúng ta sẽ start Thread với cái tên mặc định trước. Đợi Thread này chạy 1 giây sau rồi đổi tên cho nó. |