Helpex - Trao đổi & giúp đỡ Đăng nhập

Bộ đồng bộ hóa Java

Giao tiếp chủ yếu xảy ra bằng cách chia sẻ quyền truy cập vào các trường và đối tượng. Mặc dù cực kỳ hiệu quả, hình thức giao tiếp này dễ xảy ra các lỗi như nhiễu luồng và tính nhất quán của bộ nhớ . Đồng bộ hóa là một công cụ giúp ngăn ngừa những lỗi như vậy.

Tuy nhiên, đồng bộ hóa không miễn phí và có thể gây ra độ trễ khi truy cập vào một khóa hoặc đối tượng hiện đang được một luồng khác nắm giữ. Luồng chờ không thể sử dụng đối tượng đó cho đến khi luồng khác giải phóng khóa trên đối tượng. Điều kiện này được gọi là tranh chấp sợi chỉ. Nó cũng có thể dẫn đến bế tắc và sống động.

Trong bài đăng này, chúng ta sẽ khám phá các tùy chọn khác nhau mà Java cung cấp để đối phó với đồng bộ hóa luồng.

Cơ bản về đồng bộ hóa

Java cung cấp một loạt các cơ chế để xử lý đồng bộ hóa và điều phối luồng cơ bản. Nó hỗ trợ đồng bộ hóa truy cập đối tượng chi tiết thông qua và. Điều phối luồng cơ bản có thể được thực hiện thông qua. Tất cả các cơ chế được đề cập đều được xây dựng xung quanh việc mua và giải phóng khóa nội tại của đối tượng.

Khóa nội tại

Mọi đối tượng Java đều có một khóa nội tại liên quan. Một luồng cần quyền truy cập độc quyề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à sau đó giải phóng khóa nội tại khi nó được thực hiện. Các luồng khác đang cố gắng truy cập đối tượng sẽ chặn cho đến khi luồng giữ khóa giải phóng nó.

Phương pháp đồng bộ hóa

Khi một luồng gọi một phương thức được đồng bộ hóa , nó sẽ nhận được khóa nội tại cho đối tượng của phương thức đó và giải phóng nó khi các phương thức trả về. Khóa được giải phóng ngay cả khi phương thức trả về do một ngoại lệ chưa được cập nhật. Nếu được thực hiện trong một phương thức tĩnh, luồng sẽ nhận được khóa cho đối tượng lớp được liên kết với lớp.

Các câu lệnh được đồng bộ hóa

Cung cấp cơ chế đồng bộ hóa chi tiết hơn. Các câu lệnh được đồng bộ hóa phải chỉ định đối tượng cung cấp khóa nội tại. Đồng bộ hóa qua các đối tượng khóa riêng biệt có thể cung cấp đồng bộ hóa các trường mà không buộc phải đồng bộ hóa giữa các cuộc gọi phương thức.

Các khối được bảo vệ

Như đã đề cập trước đó, các khối được bảo vệ cung cấp hỗ trợ cho việc điều phối luồng. Các khối được bảo vệ là một phần của mọi đối tượng Java và có thể được xây dựng bằng cách sử dụng wait, notifynotifyAllcác phương thức.

Các waitphương pháp đình chỉ thread hiện hành. Khi một luồng gọi đợi, nó phải sở hữu khóa nội tại của đối tượng, đó là lý do tại sao các lệnh gọi chờ thường được bao bọc trong một phương thức hoặc câu lệnh được đồng bộ hóa. Việc gọi phương thức chờ sẽ tạm dừng quá trình thực thi luồng và giải phóng khóa.

Tại một thời điểm nào đó, một luồng khác sẽ có được khóa nội tại của đối tượng và gọi notifyAllđể thông báo cho tất cả các luồng đang chờ rằng điều gì đó quan trọng đã xảy ra. Sau khi luồng thứ hai đã giải phóng khóa, các luồng chờ sẽ yêu cầu lại khóa và tiếp tục thực thi bằng cách quay lại từ lệnh chờ.

Notifyđánh thức một chủ đề duy nhất. Không thể chỉ định chủ đề bê tông được đánh thức, do đó, nó chỉ hữu ích nếu chúng ta không quan tâm đến chủ đề nào được đánh thức.

Bộ đồng bộ hóa Java

Java cũng cung cấp năm lớp để đồng bộ hóa mục đích đặc biệt chung.

CountDownLatch

Lớp CountDownLatch cho phép một hoặc nhiều luồng chờ cho đến khi một tập hợp các thao tác trong các luồng khác hoàn thành. Nó được khởi tạo với một số đếm.

Các awaitphương pháp khối cho đến khi đạt số zero.

Các countDownphương pháp decrements đếm.

Khi phương thức await trả về, tất cả các luồng chờ được giải phóng và các lệnh gọi tiếp theo sẽ awaittrả về ngay lập tức. Không thể đặt lại số đếm.

Semaphore

Các Semaphore được sử dụng để hạn chế truy cập thread để một nguồn lực nhất định. Nó được khởi tạo với một số giấy phép.

Các acquirephương pháp khối cho đến khi giấy phép có sẵn và mất nó.

Các releasephương pháp bổ sung giấy phép, phát hành một thâu tóm chặn.

Lưu ý rằng các lệnh gọi để phát hành không nhất thiết phải được thực hiện bởi cùng một chủ đề được gọi là có được. Một semaphore có thể công bằng hoặc không công bằng . Nếu công bằng, thì các chủ đề có được giấy phép theo kiểu FIFO.

Mặc dù thoạt đầu nó có vẻ giống với CountDownLatch nhưng mục đích của nó là hoàn toàn khác.

CyclicBarrier

Các CyclicBarrier được xây dựng xung quanh các khái niệm về các bên . Nó cho phép các chủ đề chờ đợi nhau để đạt được một điểm rào cản chung.

Các awaitphương pháp khối cho đến khi tất cả các bên đến. Nó hoạt động bằng cách nào đó như là nghịch đảo của CountDownLatch . Sau khi N đợi nó tiếp tục.

Nó có hỗ trợ cho một có thể chạy tùy chọn chạy một lần cho mỗi điểm rào cản. Sau khi bữa tiệc cuối cùng đến, nhưng trước khi họ được giải phóng. Nó thường được sử dụng để cập nhật trạng thái chia sẻ giữa các luồng. Nó có tính chu kỳ vì nó có thể được sử dụng lại sau khi các luồng được giải phóng.

Người trao đổi

Bộ trao đổi là một điểm đồng bộ hóa mà tại đó hai luồng có thể trao đổi thông tin.

Các chuỗi khối cho đến khi đối tác của nó trình bày thông tin của nó. Hành vi giống nhau xảy ra ở cả hai phía.

Phaser

Các Phaser là một rào cản tái sử dụng, tương tự như CountDownLatchCyclirBarrier , nhưng linh hoạt hơn nhiều.

Trong phaser, số lượng các bên đã đăng ký không cố định tại thời điểm tạo. Các bên có thể đăng ký bất kỳ lúc nào thông qua registerhoặc bulkRegistercác phương thức. Các bên có thể hủy đăng ký khi đến với arriveAndDeregister.

Nó cung cấp một số phương pháp để đồng bộ hóa . Các arriveAndAwaitAdvancephương pháp xử theo cùng một cách như CycleBarrierawait phương pháp thực hiện. arrivearriveAndDeregisterghi lại lượt đến, nhưng đừng chặn. awaitAdvancekhối cho đến khi tất cả các bên đến nơi.

Nó có thể được kết thúc , buộc tất cả các phương thức đồng bộ hóa trở lại. Có thể buộc phải thông qua forceTerminationphương pháp.

Nó cũng cung cấp hỗ trợ để theo dõi trạng thái của nó. Cần lưu ý rằng các phương thức đồng bộ hóa chỉ có thể được gọi bởi các bên đã đăng ký, trong khi trạng thái có thể được giám sát bởi bất kỳ người gọi nào. Các phương pháp giám sát bao gồm getRegisteredPartiesgetArrivedPartiestrong số những phương pháp khác.

Phần kết luận

Đa luồng chắc chắn không phải là một vấn đề dễ dàng, nhưng có thể dễ dàng hơn bằng cách nào đó để giải quyết bằng cách sử dụng các công cụ mà một số ngôn ngữ cung cấp. Cá nhân tôi, tôi không cần phải sử dụng tất cả các công cụ hàng ngày, nhưng tôi nghĩ rằng điều đáng để biết rằng chúng tồn tại và chúng có thể giúp ích như thế nào.

Bài viết này được xuất bản lần đầu tiên trên  blog Codurance .

15 hữu ích 0 bình luận 20k xem chia sẻ

Có thể bạn quan tâm

loading