2011-07-24 38 views
8

Ai đó có thể xin giải thích sự khác biệt giữa hai ví dụ này trong bối cảnh đối tượng khóa:đề đồng bộ và khóa

public void method1(){ 
    synchronized(this){ 
     .... 
    } 
} 

StringBuffer aStringBufferObject = new StringBuffer("A"); 

public void method2(){ 
    synchronized(aStringBufferObject){ 
     .... 
    } 
} 

Tôi biết ví dụ đầu tiên sẽ có được một khóa trên this thể hiện và lần thứ hai sẽ nhận được một khóa của cá thể aStringBufferObject. Nhưng tôi không thực sự hiểu những gì có hiệu lực hoặc sự khác biệt của hai là.

Ví dụ, trong ví dụ thứ hai, các chuỗi sẽ vẫn có thể thực thi mã bên trong khối được đồng bộ hóa vì khóa không liên quan đến cá thể 'this'?

Tôi biết rằng việc đồng bộ hóa một phương thức hoặc một khối mã ngăn nhiều luồng truy cập khối/phương pháp đó cùng một lúc nhưng mục đích của việc chỉ định đối tượng đó là gì và sự khác biệt trong cách đối tượng được chỉ định như trong các ví dụ trên?

+1

Xem thêm [Phương pháp đồng bộ hóa và khóa luồng] (http://forums.oracle.com/forums/thread.jspa?threadID=2257647). –

+0

Cũng có một cái nhìn ở đây: [Java Concurrency/Multithreading - Hướng dẫn] (http://www.vogella.de/articles/JavaConcurrency/article.html) –

+0

@Andrew: ah, tôi mặc dù bạn đang đề cập đến một bài viết, nhưng xem ngay bây giờ là một bài đăng đa bài. –

Trả lời

8

Mục đích của việc chỉ định đối tượng cần khóa là gì?

Thường thì việc đồng bộ hóa dễ dàng hơn trên this hoặc trên trường hợp Class (đối với phương pháp tĩnh). Tuy nhiên, có những trường hợp bạn sẽ cần phải đồng bộ hóa trên một đối tượng cụ thể thay vì khóa ẩn (this). Các trường hợp này bao gồm:

  • Bạn muốn đồng bộ hóa quyền truy cập vào nguyên thủy mà không sử dụng this. Bạn chỉ có thể đồng bộ hóa trên Object s vì mỗi Object được liên kết với một màn hình ngầm trong Java. Nguyên thủy không có màn hình ngầm như vậy, và do đó bạn cần phải sử dụng một đối tượng khóa. Sử dụng các lớp trình bao bọc là một lựa chọn không đúng và sai, đặc biệt nếu bạn kết thúc modifying the lock object in the guarded block.
  • Bạn muốn đồng bộ hóa trên một đối tượng thực sự bảo vệ phần quan trọng, khi đồng bộ hóa trên this sẽ không đảm bảo an toàn luồng. Ví dụ, nếu bạn đang đồng bộ hóa quyền truy cập vào một cá thể ArrayList được chia sẻ trên các phiên bản của lớp A, thì việc đồng bộ hóa trên một cá thể của A là vô ích. Một chuỗi có thể tạo một phiên bản mới của A và có quyền truy cập vào danh sách, trong khi một luồng khác đang sửa đổi nó. Nếu bạn sử dụng một khóa khác nhau mà tất cả các chủ đề phải tranh giành thì bạn có thể bảo vệ danh sách; khóa này có thể là khóa được liên kết với A.class, nhưng có thể là bất kỳ đối tượng nào sẽ cung cấp cùng một đảm bảo.
  • Bạn muốn thực hiện chia tách khóa để đảm bảo rằng các khối được bảo vệ khác nhau được bảo vệ bằng các khóa khác nhau thay vì cùng một khóa. Nói cách khác, nếu nó là thread-an toàn để cho phép các chủ đề khác nhau để có được ổ khóa khác nhau để truy cập các phần quan trọng khác nhau, sau đó bạn có thể có một khóa khác nhau cho mỗi phần quan trọng.

Sau đây là một ví dụ về việc sử dụng khóa chia:

private Object method1Lock = new Object(); 
private Object method2Lock = new Object(); 

public void method1(){ 
    synchronized(method1Lock){ 
     .... 
    } 
} 

public void method2(){ 
    synchronized(method2Lock){ 
     .... 
    } 
} 

Bạn sẽ sử dụng khóa chia khi bạn có thể đảm bảo rằng việc thực hiện đồng thời method1method2 không vi phạm bất biến lớp. Bằng cách này, bạn có thể cải thiện hiệu suất trên các chủ đề cần truy cập vào cùng một đối tượng, nhưng sẽ gọi các phương thức khác nhau.


Về câu hỏi khác của bạn,

Ví dụ, trong ví dụ thứ hai, sẽ đề vẫn có thể thực thi mã bên trong khối đồng bộ vì khóa không liên quan đến việc 'này' ví dụ?

Trong ví dụ thứ hai, bất kỳ chuỗi nào vào khu vực được bảo vệ phải có khóa được liên kết với aStringBufferObject. Nếu một chủ đề khác đang giữ khóa đó thì luồng hiện tại sẽ không tiếp tục. Khi bạn chỉ định this, thì chuỗi phải lấy khóa được liên kết với đối tượng hiện tại. Trong cả hai trường hợp, luồng phải có khóa; các ví dụ chỉ khác nhau trong đối tượng đang được sử dụng làm khóa.

2

Đồng bộ hóa trên một đối tượng có nghĩa là các khối khác đồng bộ hóa trên cùng một đối tượng sẽ phải đợi. Ví dụ:

public void methodA() { 
    synchronized(obj) { 
     //Do one job 
    } 
} 

public void methodB() { 
    synchronized(obj) { 
     //Do another job 
    } 
} 

Nếu bạn gọi methodA() trong một thread và sau đó gọi methodB() trong chủ đề khác, methodB() sẽ không hoàn thành trước methodA() kết thúc.

2

Khối synchronized là một màn hình, để lại các chi tiết để khóa và mở khóa một mutex. Bởi vì mọi đối tượng trong Java đều có khóa bên trong (tham khảo mã nguồn của lớp Object), khi sử dụng câu lệnh synchronized, JVM sẽ giúp bạn đồng bộ hóa phần quan trọng. Bạn cũng có thể tự đồng bộ hóa khối sử dụng ReentrantLock trong gói java.util.concurrent.locks.

Các vấn đề liên quan