Hướng Dẫn Lập Trình đa Luồng Trong Java - Java Multithreading
Có thể bạn quan tâm
- Tất cả tài liệu
- Java
- Java Basic
- Java Collections Framework
- Java IO
- Java New IO
- Java Date Time
- Servlet/JSP
- Eclipse Tech
- SWT
- RCP
- RAP
- Eclipse Plugin Tools
- XML & HTML
- Java Opensource
- Java Application Servers
- Maven
- Gradle
- Servlet/Jsp
- Thymeleaf
- Spring
- Spring Boot
- Spring Cloud
- Struts2
- Hibernate
- Java Web Service
- JavaFX
- SWT
- Oracle ADF
- Android
- iOS
- Python
- Swift
- C#
- C/C++
- Ruby
- Dart
- Batch
- Database
- Oracle
- MySQL
- SQL Server
- PostGres
- Other Database
- Oracle APEX
- Report
- Client
- ECMAScript / Javascript
- TypeScript
- NodeJS
- ReactJS
- Flutter
- AngularJS
- HTML
- CSS
- Bootstrap
- OS
- Ubuntu
- Solaris
- Mac OS
- VPS
- Git
- SAP
- Amazon AWS
- Khác
- Chưa phân loại
- Phần mềm & ứng dụng tiện ích
- VirtualBox
- VmWare
- Nguyên tắc hoạt động của Thread
- Ví dụ bắt đầu với Thread
- Runnable Interface
- Luồng Deamon (Deamon Thread)
- Sử dụng join() & join(long)
- Xử lý ngoại lệ cho Thread
- Sử dụng yield()
- So sánh sleep() và wait()
1. Nguyên tắc hoạt động của Thread
2. Ví dụ bắt đầu với Thread
Chúng ta cần 2 class tham gia vào ví dụ này.- HelloMain là một class thông thường có hàm main, nó là một luồng chính (main thread).
- HelloThread là một class mở rộng từ class Thread. Nó được tạo và chạy kích hoạt chạy bên trong luồng chính và sẽ chạy song song với luồng chính.
3. Runnable Interface
Bạn cũng có thể tạo một thread từ một class thi hành interface Runnable. Xem ví dụ minh họa:RunnableDemo.javapackage org.o7planning.tutorial.thread.runnable; public class RunnableDemo implements Runnable { @Override public void run() { int idx = 1; for (int i = 0; i < 5; i++) { System.out.println("Hello from RunnableDemo " + idx++); // Ngủ 2 giây. try { Thread.sleep(2000); } catch (InterruptedException e) { } } } }RunnableTest.javapackage org.o7planning.tutorial.thread.runnable; public class RunnableTest { public static void main(String[] args) throws InterruptedException { System.out.println("Main thread running.."); // Tạo một thread từ Runnable. Thread thread = new Thread(new RunnableDemo()); thread.start(); // Ngủ 5 giây. Thread.sleep(5000); System.out.println("Main thread stopped"); } }Chạy class RunnableTest:Main thread running.. Hello from RunnableDemo 1 Hello from RunnableDemo 2 Hello from RunnableDemo 3 Main thread stopped Hello from RunnableDemo 4 Hello from RunnableDemo 54. Luồng Deamon (Deamon Thread)
Java chia thread làm 2 loại một loại thông thường và Deamon Thread. Chúng chỉ khác nhau ở cách thức ngừng hoạt động. Trong một chương trình các luồng thông thường và luồng Deamon chạy song song với nhau. Khi tất cả các luồng thông thường kết thúc, mọi luồng Deamon cũng sẽ bị kết thúc theo bất kể nó đang làm việc gì.Chú ý: Sử dụng setDeamon(boolean) để sét đặt một luồng là Deamon hoặc không. Chú ý, bạn chỉ có thể gọi hàm setDeamon(boolean) khi thread chưa được chạy. Điều đó có nghĩa là khi thread đã chạy bạn không thể chuyển luồng từ non-deamon sang deamon và ngược lại. Khi một luồng mới được tạo ra, nó được thừa hưởng đặc tính deamon từ luồng cha. Như vậy khi bạn tạo một luồng trong hàm main của 1 class nó vốn là luồng non-deamon, vì vậy thread tạo ra mặc định cũng là none-deamon. Như vậy nếu bạn tạo một luồng mới trong một luồng Deamon, mặc định nó cũng sẽ là Deamon.Thread thread = new MyThread(); // sét luồng này là deamon. // Chỉ gọi được method này khi thread chưa start. // Trong trường hợp start rồi sẽ bị một ngoại lệ. thread.setDeamon(true); // Sét luồng này là non-deamon. // Chỉ gọi được method này khi thread chưa start. // Trong trường hợp start rồi sẽ bị một ngoại lệ. thread.setDeamon(false);Để dễ hiểu chúng ta xem ví dụ sau, chúng ta cần 3 class tham gia vào minh họa:NoneDeamonThread.javapackage org.o7planning.tutorial.thread.deamon; public class NoneDeamonThread extends Thread { @Override public void run() { int i = 0; // Vòng lặp 10 lần. Luồng này sẽ kết thúc. while (i < 10) { System.out.println(" - Hello from None Deamon Thread " + i++); try { // Ngủ 1 giây. Thread.sleep(1000); } catch (InterruptedException e) { } } // Ghi ra thông báo luồng này kết thúc. System.out.println("\n==> None Deamon Thread ending\n"); } }DeamonThread.javapackage org.o7planning.tutorial.thread.deamon; class DeamonThread extends Thread { @Override public void run() { int count = 0; // Vòng lặp vô tận. while (true) { System.out.println("+ Hello from Deamon Thread " + count++); try { // Ngủ 2 giây. sleep(2000); } catch (InterruptedException e) { } } } }DaemonTest.javapackage org.o7planning.tutorial.thread.deamon; public class DaemonTest { public static void main(String[] args) { System.out.println("==> Main Thread running..\n"); // Tạo một Thread Thread deamonThread = new DeamonThread(); // Sét nó là Deamon Thread. deamonThread.setDaemon(true); deamonThread.start(); // Tạo một Thread khác new NoneDeamonThread().start(); try { // Ngủ 5 giây. Thread.sleep(5000); } catch (InterruptedException e) { } // Ghi ra thông báo luồng main này kết thúc. System.out.println("\n==> Main Thread ending\n"); } }Kết quả chạy class DeamonTest:Hình minh họa trên cho thấy rằng luồng Deamon đã bị dừng lại khi tất cả các luồng thông thường đã dừng. Mặc dù code của nó là chạy vô tận.Luồng deamon thường dùng làm gì?Một trong các luồng Deamon quan trọng của Java đó là luồng gom rác (Garbage Collection Thread), nghĩa là gom các tài nguyên không còn sử dụng để giải phóng bộ nhớ. Khi tất cả các luồng người dùng không còn hoạt động nữa luồng gom rác cũng bị dừng theo.
5. Sử dụng join() & join(long)
Thread.join() là một method thông báo rằng hãy chờ thread này hoàn thành rồi thread cha mới được tiếp tục chạy.// Thread cha cần phải đợi cho tới khi luồng này kết thúc // mới được chạy tiếp. // (Nó tương đương với gọi join(0) ) public final void join() throws InterruptedException; // Thread cha cần phải đợi 'millis' milli giây mới được tiếp tục chạy. // kể từ lúc gọi join(long). // Nếu tham số millis = 0 nghĩa là đợi cho tới khi luồng này kết thúc. public final synchronized void join(long millis) throws InterruptedException; // Thread cha cần phải đợi 'millis' milli giây và 'nanos' nano giây mới được tiếp tục chạy. // kể từ lúc gọi join(long,int). // Nếu tham số millis = 0 & nanos = 0 nghĩa là đợi cho tới khi luồng này kết thúc. // 1 giây = 1000000 nano giây. public final synchronized void join(long millis, int nanos) throws InterruptedException;Hãy xem một ví dụ minh họa:JoinThread.javapackage org.o7planning.tutorial.thread.join; public class JoinThread extends Thread { private String threadName; private int count; public JoinThread(String threadName, int count) { this.threadName = threadName; this.count = count; } @Override public void run() { for (int i = 1; i < count + 1; i++) { System.out.println("Hello from " + this.threadName + " " + i); try { Thread.sleep(2000); } catch (InterruptedException e) { } } System.out.println("\n==> Thread " + threadName + " end!\n"); } }JoinTest.javapackage org.o7planning.tutorial.thread.join; public class JoinTest { public static void main(String[] args) throws InterruptedException { System.out.println("\n==> Main thread starting..\n"); Thread joinThreadA = new JoinThread("A*", 2); Thread joinThreadB = new JoinThread("B*", 3); // Thread thông thường, sẽ không sử dụng join(). Thread noJoinThreadC = new JoinThread("C", 5); joinThreadA.start(); joinThreadB.start(); noJoinThreadC.start(); // Sử dụng join() joinThreadA.join(); joinThreadB.join(); // Đoạn code dưới đây sẽ phải chờ cho tới khi 2 // joinThread A,B hoàn thành, mới được chạy tiếp. System.out.println("Hello from main thread..."); System.out.println("Thread A isLive? " + joinThreadA.isAlive()); System.out.println("Thread B isLive? " + joinThreadB.isAlive()); System.out.println("Thread C isLive? " + noJoinThreadC.isAlive()); System.out.println("\n==> Main Thread end!\n"); } }Kết quả chạy class JoinTest:==> Main thread starting.. Hello from A* 1 Hello from C 1 Hello from B* 1 Hello from A* 2 Hello from C 2 Hello from B* 2 ==> Thread A* end! Hello from B* 3 Hello from C 3 ==> Thread B* end! Hello from C 4 Hello from main thread... Thread A isLive? false Thread B isLive? false Thread C isLive? true ==> Main Thread end! Hello from C 5 ==> Thread C end!Ví dụ sử dụng join(long millis):JoinTest2.javapackage org.o7planning.tutorial.thread.join; public class JoinTest2 { public static void main(String[] args) throws InterruptedException { System.out.println("\n==> Main thread starting..\n"); Thread joinThreadA = new JoinThread("A*", 5); joinThreadA.start(); // Luồng cha (main) phải chờ 5000 milli giây // mới được tiếp tục chạy. (Không nhất thiết phải A kết thúc) joinThreadA.join(5000); System.out.println("Main thread after 5000 milli second"); System.out.println("Hello from main thread..."); System.out.println("Thread A isLive? " + joinThreadA.isAlive()); System.out.println("\n==> Main Thread end!\n"); } }Kết quả chạy ví dụ:==> Main thread starting.. Hello from A* 1 Hello from A* 2 Hello from A* 3 Main thread after 5000 milli second Hello from main thread... Thread A isLive? true ==> Main Thread end! Hello from A* 4 Hello from A* 5 ==> Thread A* end!6. Xử lý ngoại lệ cho Thread
Phương thức Thread.setDefaultUncaughtExceptionHandler() thiết lập mặc định xử lý khi luồng đột ngột chấm dứt do một ngoại lệ còn tự do, mà không có xử lý khác đã được xác định cho luồng đó.ThreadExceptionDemo.javapackage org.o7planning.tutorial.thread.exception; import java.util.Random; public class ThreadExceptionDemo { public static class RunnableTest implements Runnable { @Override public void run() { System.out.println("Thread running .."); while (true) { Random r = new Random(); // Một số ngẫu nhiên từ 0 - 99 int i = r.nextInt(100); System.out.println("Next value " + i); try { Thread.sleep(2000); } catch (InterruptedException e) { } if (i > 70) { // Mô phỏng một ngoại lệ đã không được sử lý trong luồng. throw new RuntimeException("Have a problem..."); } } } } public static void main(String[] args) { System.out.println("==> Main thread running..."); Thread thread = new Thread(new RunnableTest()); Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("#Thread: " + t); System.out.println("#Thread exception message: " + e.getMessage()); } }); thread.start(); System.out.println("==> Main thread end..."); } }Kết quả chạy ví dụ:==> Main thread running... ==> Main thread end... Thread running .. Next value 21 Next value 42 Next value 67 Next value 18 Next value 34 Next value 40 Next value 11 Next value 1 Next value 92 #Thread: Thread[Thread-0,5,main] #Thread exception message: Have a problem...7. Sử dụng yield()
Về mặt lý thuyết, "yield" có nghĩa là để cho đi, từ bỏ, đầu hàng. Một luồng yield nói với máy ảo là nó sẵn sàng để cho các thread khác được sắp xếp ở vị trí của nó. Điều này cho thấy rằng nó không phải làm một cái gì đó quá quan trọng. Lưu ý rằng nó chỉ là một gợi ý, mặc dù, và không đảm bảo có hiệu lực ở tất cả.yield() được định nghĩa như sau trong Thread.java
public static native void yield();Như vậy phương thức yield() được sử dụng khi bạn bạn thấy rằng thread đó đang rảnh rỗi, nó không phải làm việc gì quan trọng, nên nó gợi ý hệ điều hành tạm thời nhường quyền ưu tiên cho các luồng khác.Ví dụ dưới đây, có 2 luồng, mỗi luồng in ra một dòng văn bản 100K lần (con số đủ lớn để thấy sự khác biệt). Một luồng được sét độ ưu tiên cao nhất và một luồng được sét độ ưu tiên ít nhất. Đo khoảng thời gian kết thúc của 2 luồng.YieldThreadExample.javapackage org.o7planning.tutorial.thread.yield; import java.util.Date; public class YieldThreadExample { private static Date importantEndTime; private static Date unImportantEndTime; public static void main(String[] args) { importantEndTime = new Date(); unImportantEndTime = new Date(); System.out.println("Create thread 1"); Thread importantThread = new ImportantThread(); // Sét đặt độ ưu tiên cao nhất cho thread này. importantThread.setPriority(Thread.MAX_PRIORITY); System.out.println("Create thread 2"); Thread unImportantThread = new UnImportantThread(); // Sét đặt độ ưu tiên thấp nhất cho thread này. unImportantThread.setPriority(Thread.MIN_PRIORITY); // Start threads. unImportantThread.start(); importantThread.start(); } // Một nhiệm vụ quan trọng, yêu cầu độ ưu tiên cao. static class ImportantThread extends Thread { @Override public void run() { for (int i = 0; i < 100000; i++) { System.out.println("\n Important work " + i); // Thông báo với hệ điều hành, // thread này nhường quyền ưu tiên cho các luồng khác. Thread.yield(); } // Thời điểm kết thúc của thread này. importantEndTime = new Date(); printTime(); } } static class UnImportantThread extends Thread { @Override public void run() { for (int i = 0; i < 100000; i++) { System.out.println("\n -- UnImportant work " + i); } // Thời điểm kết thúc của thread này. unImportantEndTime = new Date(); printTime(); } } private static void printTime() { // Khoảng thời gian (Mili giây). long interval = unImportantEndTime.getTime() - importantEndTime.getTime(); System.out.println("UnImportant Thread - Important Thread = " // + interval + " milliseconds"); } }Kết quả: thread có ưu tiên thấp hơn đã hoàn thành công việc trước 51 mili giây so với thread có ưu tiên cao hơn.... Important work 99995 Important work 99996 Important work 99997 Important work 99998 Important work 99999 UnImportant Thread - Important Thread = -269 milliseconds8. So sánh sleep() và wait()
TODO.Java cơ bản
- Tùy biến trình biên dịch java xử lý Annotation của bạn (Annotation Processing Tool)
- Lập trình Java theo nhóm sử dụng Eclipse và SVN
- Hướng dẫn và ví dụ Java WeakReference
- Hướng dẫn và ví dụ Java PhantomReference
- Hướng dẫn nén và giải nén trong Java
- Cấu hình Eclipse để sử dụng JDK thay vì JRE
- Phương thức String.format() và printf() trong Java
- Cú pháp và các tính năng mới trong Java 5
- Cú pháp và các tính năng mới trong Java 8
- Hướng dẫn sử dụng biểu thức chính quy trong Java
- Hướng dẫn lập trình đa luồng trong Java - Java Multithreading
- Thư viện điều khiển các loại cơ sở dữ liệu khác nhau trong Java
- Hướng dẫn sử dụng Java JDBC kết nối cơ sở dữ liệu
- Lấy các giá trị của các cột tự động tăng khi Insert một bản ghi sử dụng JDBC
- Hướng dẫn và ví dụ Java Stream
- Functional Interface trong Java
- Giới thiệu về Raspberry Pi
- Hướng dẫn và ví dụ Java Predicate
- Abstract class và Interface trong Java
- Access modifier trong Java
- Hướng dẫn và ví dụ Java Enum
- Hướng dẫn và ví dụ Java Annotation
- So sánh và sắp xếp trong Java
- Hướng dẫn và ví dụ Java String, StringBuffer và StringBuilder
- Hướng dẫn xử lý ngoại lệ trong Java - Java Exception Handling
- Hướng dẫn và ví dụ Java Generics
- Thao tác với tập tin và thư mục trong Java
- Hướng dẫn và ví dụ Java BiPredicate
- Hướng dẫn và ví dụ Java Consumer
- Hướng dẫn và ví dụ Java BiConsumer
- Bắt đầu với Java cần những gì?
- Lịch sử của Java và sự khác biệt giữa Oracle JDK và OpenJDK
- Cài đặt Java trên Windows
- Cài đặt Java trên Ubuntu
- Cài đặt OpenJDK trên Ubuntu
- Cài đặt Eclipse
- Cài đặt Eclipse trên Ubuntu
- Học nhanh Java cho người mới bắt đầu
- Lịch sử của bit và byte trong khoa học máy tính
- Các kiểu dữ liệu trong Java
- Các toán tử Bitwise
- Câu lệnh rẽ nhánh (if else) trong Java
- Câu lệnh rẽ nhánh switch trong Java
- Vòng lặp trong Java
- Mảng (Array) trong Java
- JDK Javadoc định dạng CHM
- Thừa kế và đa hình trong Java
- Hướng dẫn và ví dụ Java Function
- Hướng dẫn và ví dụ Java BiFunction
- Ví dụ về Java encoding và decoding sử dụng Apache Base64
- Hướng dẫn và ví dụ Java Reflection
- Hướng dẫn gọi phương thức từ xa với Java RMI
- Hướng dẫn lập trình Java Socket
- Các nền tảng nào bạn nên chọn để lập trình ứng dụng Java Desktop?
- Hướng dẫn và ví dụ Java Commons IO
- Hướng dẫn và ví dụ Java Commons Email
- Hướng dẫn và ví dụ Java Commons Logging
- Tìm hiểu về Java System.identityHashCode, Object.hashCode và Object.equals
- Hướng dẫn và ví dụ Java SoftReference
- Hướng dẫn và ví dụ Java Supplier
- Lập trình Java hướng khía cạnh với AspectJ (AOP)
- Hướng dẫn lập trình Java Servlet/JSP
- Các hướng dẫn Java Collections Framework
- Java API cho HTML & XML
- Các hướng dẫn Java IO
- Các hướng dẫn Java Date Time
- Các hướng dẫn Spring Boot
- Các hướng dẫn Maven
- Các hướng dẫn Gradle
- Các hướng dẫn Java Web Services
- Các hướng dẫn lập trình Java SWT
- Các hướng dẫn lập trình JavaFX
- Các hướng dẫn Java Oracle ADF
- Các hướng dẫn Struts2 Framework
- Các hướng dẫn Spring Cloud
Java cơ bản
- Tùy biến trình biên dịch java xử lý Annotation của bạn (Annotation Processing Tool)
- Lập trình Java theo nhóm sử dụng Eclipse và SVN
- Hướng dẫn và ví dụ Java WeakReference
- Hướng dẫn và ví dụ Java PhantomReference
- Hướng dẫn nén và giải nén trong Java
- Cấu hình Eclipse để sử dụng JDK thay vì JRE
- Phương thức String.format() và printf() trong Java
- Cú pháp và các tính năng mới trong Java 5
- Cú pháp và các tính năng mới trong Java 8
- Hướng dẫn sử dụng biểu thức chính quy trong Java
- Hướng dẫn lập trình đa luồng trong Java - Java Multithreading
- Thư viện điều khiển các loại cơ sở dữ liệu khác nhau trong Java
- Hướng dẫn sử dụng Java JDBC kết nối cơ sở dữ liệu
- Lấy các giá trị của các cột tự động tăng khi Insert một bản ghi sử dụng JDBC
- Hướng dẫn và ví dụ Java Stream
- Functional Interface trong Java
- Giới thiệu về Raspberry Pi
- Hướng dẫn và ví dụ Java Predicate
- Abstract class và Interface trong Java
- Access modifier trong Java
- Hướng dẫn và ví dụ Java Enum
- Hướng dẫn và ví dụ Java Annotation
- So sánh và sắp xếp trong Java
- Hướng dẫn và ví dụ Java String, StringBuffer và StringBuilder
- Hướng dẫn xử lý ngoại lệ trong Java - Java Exception Handling
- Hướng dẫn và ví dụ Java Generics
- Thao tác với tập tin và thư mục trong Java
- Hướng dẫn và ví dụ Java BiPredicate
- Hướng dẫn và ví dụ Java Consumer
- Hướng dẫn và ví dụ Java BiConsumer
- Bắt đầu với Java cần những gì?
- Lịch sử của Java và sự khác biệt giữa Oracle JDK và OpenJDK
- Cài đặt Java trên Windows
- Cài đặt Java trên Ubuntu
- Cài đặt OpenJDK trên Ubuntu
- Cài đặt Eclipse
- Cài đặt Eclipse trên Ubuntu
- Học nhanh Java cho người mới bắt đầu
- Lịch sử của bit và byte trong khoa học máy tính
- Các kiểu dữ liệu trong Java
- Các toán tử Bitwise
- Câu lệnh rẽ nhánh (if else) trong Java
- Câu lệnh rẽ nhánh switch trong Java
- Vòng lặp trong Java
- Mảng (Array) trong Java
- JDK Javadoc định dạng CHM
- Thừa kế và đa hình trong Java
- Hướng dẫn và ví dụ Java Function
- Hướng dẫn và ví dụ Java BiFunction
- Ví dụ về Java encoding và decoding sử dụng Apache Base64
- Hướng dẫn và ví dụ Java Reflection
- Hướng dẫn gọi phương thức từ xa với Java RMI
- Hướng dẫn lập trình Java Socket
- Các nền tảng nào bạn nên chọn để lập trình ứng dụng Java Desktop?
- Hướng dẫn và ví dụ Java Commons IO
- Hướng dẫn và ví dụ Java Commons Email
- Hướng dẫn và ví dụ Java Commons Logging
- Tìm hiểu về Java System.identityHashCode, Object.hashCode và Object.equals
- Hướng dẫn và ví dụ Java SoftReference
- Hướng dẫn và ví dụ Java Supplier
- Lập trình Java hướng khía cạnh với AspectJ (AOP)
- Hướng dẫn lập trình Java Servlet/JSP
- Các hướng dẫn Java Collections Framework
- Java API cho HTML & XML
- Các hướng dẫn Java IO
- Các hướng dẫn Java Date Time
- Các hướng dẫn Spring Boot
- Các hướng dẫn Maven
- Các hướng dẫn Gradle
- Các hướng dẫn Java Web Services
- Các hướng dẫn lập trình Java SWT
- Các hướng dẫn lập trình JavaFX
- Các hướng dẫn Java Oracle ADF
- Các hướng dẫn Struts2 Framework
- Các hướng dẫn Spring Cloud
Các bài viết mới nhất
- Xử lý lỗi 404 trong Flutter GetX
- Ví dụ đăng nhập và đăng xuất với Flutter Getx
- Hướng dẫn và ví dụ Flutter NumberTextInputFormatter
- Hướng dẫn và ví dụ Flutter multi_dropdown
- Hướng dẫn và ví dụ Flutter flutter_form_builder
- Hướng dẫn và ví dụ Flutter GetX obs Obx
- Hướng dẫn và ví dụ Flutter GetX GetBuilder
- Từ khoá part và part of trong Dart
- Hướng dẫn và ví dụ Flutter InkWell
- Bài thực hành Flutter SharedPreferences
- Hướng dẫn và ví dụ Flutter Radio
- Hướng dẫn và ví dụ Flutter Slider
- Hướng dẫn và ví dụ Flutter SkeletonLoader
- Chỉ định cổng cố định cho Flutter Web trên Android Studio
- Hướng dẫn và ví dụ Flutter SharedPreferences
- Tạo Module trong Flutter
- Flutter upload ảnh sử dụng http và ImagePicker
- Bài thực hành Dart http CRUD
- Hướng dẫn và ví dụ Flutter image_picker
- Flutter GridView với SliverGridDelegate tuỳ biến
- Java cơ bản
Từ khóa » đa Luồng Thread Java
-
Lập Trình đa Luồng Trong Java (Java Multi-threading) - TopDev
-
Tìm Hiểu Về Xử Lí đa Luồng Trong Java - Viblo
-
Thread Trong Java - Học Java Miễn Phí Hay Nhất - VietTuts
-
Tất Tần Tật Về Thread (Luồng) Trong Java Bạn Nên Biết - ITNavi
-
Lập Trình Đa Luồng Trong JAVA - NIIT - ICT Hà Nội
-
Bài 31: Đa Luồng Trong Java - Lập Trình Java Cơ Bản
-
Bài Toán đa Luồng (MultiThreading In Java) đọc File Trong Java
-
Lập Trình đa Luồng Với Thread Trong Java | Tìm ở đây
-
Thread Trong Java Là Gì Và Ưu Nhược Điểm Của Nó? - CodeLearn
-
Đa Luồng Nhanh Hay Chậm? - CodeLearn
-
[PDF] CHƯƠNG 3: QUẢN LÝ TIẾN TRÌNH VÀ LUỒNG - SOICT
-
Thread Trong Java
-
Lập Trình đa Luồng (multi-thread Programming
-
Đa Luồng (Multithreading) - VOER