Syncđồng hồ hóa trong Java
Là gì Syncđồng hồ hóa trong Java?
In Java, đồng bộ hóa đề cập đến khả năng kiểm soát quyền truy cập của nhiều luồng vào bất kỳ tài nguyên chia sẻ nào. Đây là tùy chọn lý tưởng khi chúng ta muốn chỉ cho phép một luồng truy cập vào tài nguyên chia sẻ.
Cách tiếp cận thực hiện này thường được gọi là lập trình `không đồng bộ`. Ngoài ra còn có các luồng trên các bộ xử lý này, là các quy trình nhẹ có thể thực hiện các lệnh đồng thời.
các loại Syncsự hóa thân
Có hai loại phương pháp đồng bộ hóa trong Java:
1) Đồng bộ hóa quy trình
2) Đồng bộ hóa luồng.
Hãy cùng nghiên cứu Thread và Đồng bộ hóa quy trình chi tiết.
Đồng bộ hóa quy trình: Nó quản lý việc đồng bộ hóa giữa các chương trình. Ví dụ, các chương trình như `Microsoft Word` và `Acrobat reader` chạy dưới dạng các tiến trình riêng lẻ.
Đồng bộ hóa luồng: Việc thực thi đồng thời tài nguyên quan trọng bởi hai hoặc nhiều Chủ đề được gọi là Chủ đề Syncđồng hồ hóa. Bạn có thể được nhóm thêm để giao tiếp loại trừ lẫn nhau và liên luồng.
Khóa trong là gì Java?
Khóa lại Java được xây dựng xung quanh một thực thể bên trong được gọi là màn hình hoặc khóa. Tất cả các đối tượng đều có một khóa liên kết với chúng. Vì vậy, luồng cần quyền truy cập nhất quán vào các trường của đối tượng phải có được khóa của đối tượng trước khi truy cập chúng và nó sẽ giải phóng khóa khi công việc hoàn thành. Điều này đảm bảo rằng tại một thời điểm chỉ có một luồng truy cập vào dữ liệu được chia sẻ.
Chương trình đa luồng với đồng bộ hóa
Một chương trình đa luồng là một phương pháp hoặc khối được bảo vệ khỏi sự can thiệp từ các luồng khác chia sẻ cùng một tài nguyên được chỉ định bằng từ khóa `synchronized`.
Sử dụng phương pháp đồng bộ
Bất kỳ phương thức nào được khai báo là synchronized đều được gọi là synchronized Method. Nó cũng được sử dụng để khóa một đối tượng cho bất kỳ tài nguyên được chia sẻ nào. Vì vậy, khi một luồng gọi một phương thức synchronized. Nó tự động chiếm giữ khóa cho đối tượng đó và giải phóng khi hoàn thành nhiệm vụ của mình.
Lưu ý: Từ khóa synchronized không thể hoạt động với các lớp và biến. Chỉ có thể sử dụng các phương thức và khối với từ khóa.
Tại sao sử dụng SyncPhương pháp đồng hồ hóa?
- Nó được sử dụng để khóa một đối tượng đối với bất kỳ tài nguyên được chia sẻ nào.
- Đối tượng sẽ được khóa bất cứ khi nào phương thức synchronized được gọi.
- Khóa không mở cho đến khi luồng hoàn thành chức năng của nó
Cú pháp:
Acess_modifiers synchronized return_type method_name (Method_Parameters) { }
class MathService { synchronized void getSumOfArray(int[] numbers) { int sum = 0; for (int number : numbers) { System.out.println(Thread.currentThread() .getName() + " adds " + sum + " to " + number + " to get -> " + (sum += number)); try { Thread.sleep(500); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } public class Synchronization { public static void main(String[] args) { MathService mathService = new MathService(); Thread threadOne = new Thread(() -> mathService.getSumOfArray(new int[]{10, 11, 12})); Thread threadTwo = new Thread(() -> mathService.getSumOfArray(new int[]{20, 21, 22})); threadOne.start(); threadTwo.start(); } }
Giải thích mã:
Chạy ví dụ này và quan sát rằng luồng `0` nhận khóa của đối tượng `mathService` trước và chỉ sử dụng khóa này cho đến khi nó thực thi xong. Chủ đề `0` và `1` không được xen kẽ trong mã này. Đầu ra như hình dưới đây.
Đầu ra:
Thread-0 adds 0 to 10 to get -> 10 Thread-0 adds 10 to 11 to get -> 21 Thread-0 adds 21 to 12 to get -> 33 Thread-1 adds 0 to 20 to get -> 20 Thread-1 adds 20 to 21 to get -> 41 Thread-1 adds 41 to 22 to get -> 63
Sử dụng khối đồng bộ
Giả sử bạn không muốn đồng bộ toàn bộ phương pháp. Thay vào đó, bạn muốn đồng bộ một vài dòng mã. Vào thời điểm đó, Synckhối hronized giúp đồng bộ hóa được chọn Java Mã. SyncKhóa phương thức đồng bộ hóa được truy cập trên phương thức, trong khi khóa khối đồng bộ hóa được truy cập trên đối tượng.
class MathService { void getSumOfArray(int[] numbers) { synchronized (this){ int sum = 0; for (int number : numbers) { System.out.println(Thread.currentThread() .getName() + " adds " + sum + " to " + number + " to get -> " + (sum += number)); try { Thread.sleep(500); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } } public class Synchronization { public static void main(String[] args) { MathService mathService = new MathService(); Thread threadOne = new Thread(() -> mathService.getSumOfArray(new int[]{10, 11, 12})); Thread threadTwo = new Thread(() -> mathService.getSumOfArray(new int[]{20, 21, 22})); threadOne.start(); threadTwo.start(); } }
Giải thích mã:
Khi chạy mã này, bạn sẽ thấy rằng nó hoạt động mà không có bất kỳ sự can thiệp nào. Trong phương thức synchronized, khóa được áp dụng bởi phương thức, nhưng trong khối synchronized, khóa được áp dụng bởi đối tượng. Đảm bảo đầu ra như hiển thị bên dưới.
Đầu ra:
Thread-0 adds 0 to 10 to get -> 10 Thread-0 adds 10 to 11 to get -> 21 Thread-0 adds 21 to 12 to get -> 33 Thread-1 adds 0 to 20 to get -> 20 Thread-1 adds 20 to 21 to get -> 41 Thread-1 adds 41 to 22 to get -> 63
Giải thích mã:
Khi bạn chạy mã này, bạn sẽ thấy rằng nó hoạt động mà không có sự can thiệp, đó là điều chúng ta mong đợi. Trong phương thức synchronized, khóa được áp dụng bởi phương thức, nhưng trong phương thức synchronized block, khóa được áp dụng bởi đối tượng.
Sử dụng đồng bộ hóa tĩnh
In Java đồng bộ hóa, nếu có nhiều hơn một đối tượng, hai luồng có thể lấy khóa và nhập khối hoặc khối đồng bộ hóa, với khóa riêng cho mỗi đối tượng. Để tránh điều này, có thể sử dụng đồng bộ hóa tĩnh. Synctừ khóa được đồng bộ hóa sẽ được sử dụng trước các phương thức tĩnh.
Lưu ý: Trong đồng bộ hóa tĩnh, quyền truy cập khóa nằm ở lớp, không phải ở đối tượng và phương thức.
Mã để chứng minh vấn đề khóa nhiều đối tượng
class MathService { synchronized void getSumOfArray(int[] numbers) { int sum = 0; for (int number : numbers) { System.out.println(Thread.currentThread() .getName() + " adds " + sum + " to " + number + " to get -> " + (sum += number)); try { Thread.sleep(500); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } public class Synchronization { public static void main(String[] args) { MathService mathService = new MathService(); MathService mathService1 = new MathService(); Thread threadOne = new Thread(() -> mathService.getSumOfArray(new int[]{10, 11, 12})); Thread threadTwo = new Thread(() -> mathService.getSumOfArray(new int[]{20, 21, 22})); Thread threadThree = new Thread(() -> mathService1.getSumOfArray(new int[]{10, 11, 12})); Thread threadFour = new Thread(() -> mathService1.getSumOfArray(new int[]{20, 21, 22})); threadOne.start(); threadTwo.start(); threadThree.start(); threadFour.start(); } }
Giải thích mã:
Khi chúng tôi tạo một phiên bản khác của `MathService`, chúng tôi tạo ra sự can thiệp vào các luồng vì chúng sẽ được xen kẽ với hai đối tượng. Lưu ý rằng luồng `0` và luồng `2` được xen kẽ với hai đối tượng, trong khi luồng `1` và `3` được xen kẽ với hai đối tượng.
Đầu ra:
Thread-0 adds 0 to 10 to get -> 10 Thread-2 adds 0 to 10 to get -> 10 Thread-0 adds 10 to 11 to get -> 21 Thread-2 adds 10 to 11 to get -> 21 Thread-0 adds 21 to 12 to get -> 33 Thread-2 adds 21 to 12 to get -> 33 Thread-1 adds 0 to 20 to get -> 20 Thread-3 adds 0 to 20 to get -> 20 Thread-1 adds 20 to 21 to get -> 41 Thread-3 adds 20 to 21 to get -> 41 Thread-1 adds 41 to 22 to get -> 63 Thread-3 adds 41 to 22 to get -> 63
Mã tương tự sử dụng phương thức tĩnh đồng bộ
class MathService { synchronized static void getSumOfArray(int[] numbers) { int sum = 0; for (int number : numbers) { System.out.println(Thread.currentThread() .getName() + " adds " + sum + " to " + number + " to get -> " + (sum += number)); try { Thread.sleep(500); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } public class Synchronization { public static void main(String[] args) { MathService mathService = new MathService(); MathService mathService1 = new MathService(); Thread threadOne = new Thread(() -> mathService.getSumOfArray(new int[]{10, 11, 12})); Thread threadTwo = new Thread(() -> mathService.getSumOfArray(new int[]{20, 21, 22})); Thread threadThree = new Thread(() -> mathService1.getSumOfArray(new int[]{10, 11, 12})); Thread threadFour = new Thread(() -> mathService1.getSumOfArray(new int[]{20, 21, 22})); threadOne.start(); threadTwo.start(); threadThree.start(); threadFour.start(); } }
Chạy đoạn mã trên và lưu ý rằng hiện tại chúng tôi đã loại bỏ hiện tượng nhiễu luồng. Đầu ra của mã được hiển thị dưới đây.
Đầu ra:
Thread-0 adds 0 to 10 to get -> 10 Thread-0 adds 10 to 11 to get -> 21 Thread-0 adds 21 to 12 to get -> 33 Thread-3 adds 0 to 20 to get -> 20 Thread-3 adds 20 to 21 to get -> 41 Thread-3 adds 41 to 22 to get -> 63 Thread-2 adds 0 to 10 to get -> 10 Thread-2 adds 10 to 11 to get -> 21 Thread-2 adds 21 to 12 to get -> 33 Thread-1 adds 0 to 20 to get -> 20 Thread-1 adds 20 to 21 to get -> 41 Thread-1 adds 41 to 22 to get -> 63
Ưu điểm của việc sử dụng đồng bộ hóa
Dưới đây là những lợi ích khi làm việc với các ứng dụng đồng thời:
- Mục tiêu chính của việc đồng bộ hóa trong Java là ngăn chặn dữ liệu không nhất quán bằng cách ngăn chặn sự can thiệp của luồng.
- Từ khóa đồng bộ trong Java cung cấp chức năng khóa, đảm bảo quyền truy cập loại trừ lẫn nhau vào tài nguyên được chia sẻ và ngăn ngừa tình trạng tranh giành dữ liệu.
- Nó cũng ngăn chặn việc sắp xếp lại các câu lệnh mã bởi trình biên dịch, điều này có thể gây ra sự cố đồng thời tinh vi nếu chúng ta không sử dụng từ khóa volatile hoặc synchronized.
- SyncTừ khóa hronized đọc dữ liệu từ bộ nhớ chính hơn bộ đệm và khi nó nhả khóa.
- Nó cũng xóa các thao tác ghi từ bộ nhớ chính, loại bỏ các lỗi không nhất quán trong bộ nhớ.
Nhược điểm của SyncCơ chế đồng hồ hóa
SyncCơ chế đồng hồ hóa có hiệu suất kém.
Ví dụ
- Giả sử có năm quy trình A1, A2, A3, A4 và A5.
- Họ đang chờ các tài nguyên được chia sẻ truy cập vào từng luồng một.
- Tất cả các tiến trình đều được giữ chờ, vì vậy tiến trình cuối cùng trong hàng đợi phải đợi cho đến khi tất cả các tiến trình khác hoàn tất.
Tổng kết
- Syncđồng bộ hóa đề cập đến khả năng kiểm soát quyền truy cập của nhiều luồng vào bất kỳ tài nguyên được chia sẻ nào.
- Java có hai loại phương pháp đồng bộ hóa: 1) Đồng bộ hóa quy trình và 2) Đồng bộ hóa luồng.
- Khóa lại Java được xây dựng xung quanh một thực thể bên trong được gọi là màn hình hoặc khóa.
- Chương trình đa luồng là một phương pháp hoặc khối được bảo vệ khỏi sự can thiệp từ các luồng khác chia sẻ cùng một tài nguyên được chỉ định bằng từ khóa `synchronized`.
- Bất kỳ phương thức nào được khai báo là đồng bộ hóa đều được gọi là phương thức đồng bộ hóa.
- In Java, khóa phương thức đồng bộ được truy cập trên phương thức, trong khi khóa khối đồng bộ được truy cập trên đối tượng.
- Trong đồng bộ hóa tĩnh, quyền truy cập khóa nằm ở lớp, không phải ở đối tượng và phương thức.
- Mục tiêu chính của việc đồng bộ hóa trong Java là ngăn chặn dữ liệu không nhất quán bằng cách ngăn chặn sự can thiệp của luồng.
- Hạn chế lớn nhất của phương pháp này là tất cả các quy trình đều được giữ ở trạng thái chờ, do đó quy trình cuối cùng trong hàng đợi phải đợi cho đến khi tất cả các quy trình khác hoàn tất.