Nếu một phương thức đồng bộ gọi một phương thức đồng bộ khác, thì nó có an toàn không?
void synchronized method1() {
method2()
}
void synchronized method2() {
}
Nếu một phương thức đồng bộ gọi một phương thức đồng bộ khác, thì nó có an toàn không?
void synchronized method1() {
method2()
}
void synchronized method2() {
}
Câu trả lời:
Có, khi bạn đánh dấu các phương thức là synchronized
, thì bạn thực sự đang làm điều này:
void method1() {
synchronized (this) {
method2()
}
}
void method2() {
synchronized (this) {
}
}
Khi cuộc gọi luồng đi vào method2 từ method1, thì nó sẽ đảm bảo rằng nó giữ khóa this
mà nó sẽ có, và sau đó nó có thể đi qua.
Khi luồng truy cập trực tiếp vào method1 hoặc method2, thì nó sẽ chặn cho đến khi nó có thể nhận được khóa ( this
), và sau đó nó sẽ vào.
Như James Black đã lưu ý trong phần nhận xét, bạn phải nhận thức được những gì bạn làm bên trong thân phương thức.
private final List<T> data = new ArrayList<T>();
public synchronized void method1() {
for (T item : data) {
// ..
}
}
public void method3() {
data.clear();
}
Đột nhiên, nó không an toàn luồng vì bạn đang xem xét một ConcurrentModificationException
trong tương lai của mình vì method3
nó không được đồng bộ hóa và do đó có thể được gọi bởi Thread A trong khi Thread B đang hoạt động method1
.
method3
hiển thị các hoạt động phân luồng không an toàn, nhưng bạn đang chú ý đến quá trình đồng bộ hóa nhập lại.
Là một phương thức được đánh dấu bằng cuộc gọi đồng bộ khác một chuỗi phương thức đồng bộ an toàn.
Nói chung là không thể nói trước được. Nó phụ thuộc vào những gì các phương thức làm và những gì các phương thức khác trên cùng một lớp và các lớp khác làm.
Tuy nhiên, chúng ta có thể chắc chắn rằng các lệnh gọi tới method1 và method2 trên cùng một đối tượng được thực hiện bởi các luồng khác nhau sẽ không thực thi đồng thời. Tùy thuộc vào những gì các phương thức làm, điều này có thể đủ để nói rằng lớp là an toàn theo luồng đối với các phương thức này.
Từ trang Hướng dẫn Java http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
Không thể để hai lệnh gọi của các phương thức đồng bộ trên cùng một đối tượng xen kẽ nhau. Khi một luồng đang thực thi một phương thức đồng bộ cho một đối tượng, tất cả các luồng khác gọi các phương thức đồng bộ cho cùng một khối đối tượng (tạm ngừng thực thi) cho đến khi luồng đầu tiên được thực hiện với đối tượng.
khi một phương thức được đồng bộ hóa thoát ra, nó sẽ tự động thiết lập mối quan hệ xảy ra trước với bất kỳ lệnh gọi nào tiếp theo của một phương thức đồng bộ hóa cho cùng một đối tượng. Điều này đảm bảo rằng các thay đổi đối với trạng thái của đối tượng được hiển thị cho tất cả các luồng
Vì vậy, Java sẽ đảm bảo rằng nếu 2 luồng đang thực thi cùng một phương thức, các phương thức sẽ không được thực thi đồng thời mà nối tiếp nhau.
Nhưng bạn cần lưu ý về vấn đề Liveness, http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html
Và cho dù bạn đang khóa không liên tục, nguyên nhân trong mã bạn đã sử dụng , mã này khóa toàn bộ đối tượng, nếu đối tượng của bạn chỉ cần quyền truy cập đồng bộ vào một biến, bạn chỉ nên khóa biến đó.
synchronized (this.someVar)
bạn đang tìm kiếm đối tượng có tham chiếu được lưu giữ someVar
. Sự phân biệt là rất quan trọng.