Thread Synchronization trong Java
Khi chúng ta bắt đầu hai hoặc nhiều thread bên trong một chương trình, có thể có tình huống khi nhiều thread cố gắng truy cập cùng một nguồn và cuỗi cùng chúng có thể đưa ra kết quả không như dự kiến do sự xảy ra đồng thời. Ví dụ, nếu nhiều thread cố gắng ghi vào trong cùng một file, thì khi đó chúng có thể làm ngắt dữ liệu, bởi vì một trong các thread có thể override dữ liệu hoặc trong khi một thread mở file cùng thời điểm với thread khác đang đóng file này.
Vì thế, nó là cần thiết để đồng bộ hoạt đồng của nhiều thread và đảm bảo rằng chỉ có một thread có thể truy cập nguồn tại một thời điểm. Điều này được triển khai bởi sử dụng một khái niệm được gọi là monitors. Mỗi đối tượng trong Java được xem như là một monitor, mà một thread có thể lock hoặc unlock. Chỉ có một thread tại một thời điểm có thể giữ một lock trên một monitor.
Để hiểu sâu hơn các khái niệm được trình bày trong chương này, mời bạn tham khảo loạt bài: Ví dụ về Thread trong Java.
Ngôn ngữ lập trình Java cung cấp một cách rất thuận tiện để tạo các thread và đồng bộ hóa tác vụ của chúng bởi sử dụng các khối synchronized. Bạn giữ nguồn chia sẻ (shared resource) bên trong block này. Sau đây là form chung của lệnh synchronized trong Java.
synchronized(objectidentifier) { // Access shared variables and other shared resources }
Tại đây, objectidentifier là một tham chiếu tới một đối tượng, mà có lock liên kết với monitor, mà lệnh synchronized biểu diễn. Bây giờ, chúng ta sẽ xem xét 2 ví dụ, mà sẽ in một bộ đếm (counter) bởi sử dụng 2 thread khác nhau. Khi các thread chưa được synchronized, chúng in giá trị counter mà không liên tục, nhưng khi chúng ta in counter bởi việc đặt bên trong khối synchronized(), thì nó in counter theo dãy liên tục cho cả hai thread.
Ví dụ về đa luồng mà không sử dụng Synchronization trong Java
Ví dụ đơn giản sau có thể hoặc không thể in giá trị counter liên tục và mỗi lần chúng ta chạy nó, nó cho kết quả khác nhau dựa vào tính khả dụng của CPU tới một thread.
class PrintDemo { public void printCount(){ try { for(int i = 5; i > 0; i--) { System.out.println("Counter --- " + i ); } } catch (Exception e) { System.out.println("Thread interrupted."); } }}class ThreadDemo extends Thread { private Thread t; private String threadName; PrintDemo PD; ThreadDemo( String name, PrintDemo pd){ threadName = name; PD = pd; } public void run() { PD.printCount(); System.out.println("Thread " + threadName + " exiting."); } public void start () { System.out.println("Starting " + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } }}public class TestThread { public static void main(String args[]) { PrintDemo PD = new PrintDemo(); ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD ); ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD ); T1.start(); T2.start(); // wait for threads to end try { T1.join(); T2.join(); } catch( Exception e) { System.out.println("Interrupted"); } } }
Nó sẽ cho kết quả khác nhau mỗi lần chúng ta chạy chương trình này:
Starting Thread - 1 Starting Thread - 2 Counter --- 5 Counter --- 4 Counter --- 3 Counter --- 5 Counter --- 2 Counter --- 1 Counter --- 4 Thread Thread - 1 exiting. Counter --- 3 Counter --- 2 Counter --- 1 Thread Thread - 2 exiting.
Ví dụ về đa luồng với Synchronization trong Java
Trong ví dụ sau, chúng tôi sử dụng lệnh synchronized trong Java, mà sẽ in giá trị counter liên tục và cho cùng kết quả mỗi lần chúng ta chạy chương trình.
class PrintDemo { public void printCount(){ try { for(int i = 5; i > 0; i--) { System.out.println("Counter --- " + i ); } } catch (Exception e) { System.out.println("Thread interrupted."); } }}class ThreadDemo extends Thread { private Thread t; private String threadName; PrintDemo PD; ThreadDemo( String name, PrintDemo pd){ threadName = name; PD = pd; } public void run() { synchronized(PD) { PD.printCount(); } System.out.println("Thread " + threadName + " exiting."); } public void start () { System.out.println("Starting " + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } }}public class TestThread { public static void main(String args[]) { PrintDemo PD = new PrintDemo(); ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD ); ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD ); T1.start(); T2.start(); // wait for threads to end try { T1.join(); T2.join(); } catch( Exception e) { System.out.println("Interrupted"); } } }
Nó sẽ cho cùng một kết quả mỗi khi chạy chương trình này:
Starting Thread - 1 Starting Thread - 2 Counter --- 5 Counter --- 4 Counter --- 3 Counter --- 2 Counter --- 1 Thread Thread - 1 exiting. Counter --- 5 Counter --- 4 Counter --- 3 Counter --- 2 Counter --- 1 Thread Thread - 2 exiting.
Đã có app VietJack trên điện thoại, giải bài tập SGK, SBT Soạn văn, Văn mẫu, Thi online, Bài giảng....miễn phí. Tải ngay ứng dụng trên Android và iOS.
Theo dõi chúng tôi miễn phí trên mạng xã hội facebook và youtube:Các bạn có thể mua thêm khóa học JAVA CORE ONLINE VÀ ỨNG DỤNG cực hay, giúp các bạn vượt qua các dự án trên trường và đi thực tập doanh nghiệp với Java. Khóa học có giá chỉ 400K, nhằm ưu đãi, tạo điều kiện cho sinh viên cho thể mua khóa học.
Nội dung khóa học gồm 16 chuơng và 100 video cực hay, học trực tiếp tại https://www.udemy.com/tu-tin-di-lam-voi-kien-thuc-ve-java-core-toan-tap/ Bạn nào có nhu cầu mua, inbox trực tiếp chị Thu, trợ lý anh Tuyền để hỗ trợ thanh toán qua mã QR ngân hàng Việt Nam, fb: https://www.facebook.com/Thule.59
Anh Tuyền, tác giả khóa học, là cựu sinh viên chương trình đào tạo kĩ sư tài năng của đại học Bách Khoa Hà Nội với hơn 5 năm kinh nghiệm đi làm thực tế doanh nghiệp và cũng là Founder website vietjack.com, web giáo dục phổ biến nhất Việt Nam hiện tại (năm 2024). Java cũng là ngôn ngữ lập trình dễ đi xin việc nhất hiện tại, với mức lương cao, hãy nâng cao kiến thức IT của bản thân mình vì một Việt Nam giàu mạnh.
Loạt bài hướng dẫn của chúng tôi dựa một phần trên nguồn tài liệu của: Tutorialspoint.com
Bài học Java phổ biến tại vietjack.com: