Các phương thức tĩnh được đồng bộ hóa Java: khóa trên đối tượng hoặc lớp


148

Tài liệu Java nói:

Không thể có hai yêu cầu của các phương thức được đồng bộ hóa trên cùng một đối tượng để xen kẽ.

Điều này có nghĩa gì đối với một phương thức tĩnh? Vì một phương thức tĩnh không có đối tượng liên quan, nên khóa từ khóa được đồng bộ hóa trên lớp, thay vì đối tượng?

Câu trả lời:


129

Vì một phương thức tĩnh không có đối tượng liên quan, nên khóa từ khóa được đồng bộ hóa trên lớp, thay vì đối tượng?

Đúng. :)


81
Hãy trả lời Xây dựng để mọi người có thể hiểu.
Madhu

6
@Madhu. Điều đó có nghĩa là nếu bạn có 2 hoặc nhiều phương thức được đồng bộ hóa trên cùng một lớp, cả hai đều không thể thực thi cùng một lúc, ngay cả khi có nhiều phiên bản của lớp đó. Khóa về cơ bản giống như khóa trên Object. Class cho mỗi phương thức được đồng bộ hóa.
Steven

Câu trả lời này là sai - thislà khóa có được trên các phương thức ví dụ-, vui lòng sửa nó thành Oscar.
vemv

1
@vemv Câu hỏi liên quan đến các phương thức lớp, không phải phương thức cá thể.
OscarRyz

23
@vemv Vâng, để hiểu câu trả lời bạn phải đọc câu hỏi trước.
OscarRyz

199

Chỉ cần thêm một chút chi tiết vào câu trả lời của Oscar (rất ngắn gọn!), Phần có liên quan trên Đặc tả ngôn ngữ Java là 8.4.3.6, 'Phương thức được đồng bộ hóa' :

Một phương thức được đồng bộ hóa có được một màn hình ( §17.1 ) trước khi nó thực thi. Đối với phương thức lớp (tĩnh), trình giám sát được liên kết với đối tượng Lớp cho lớp của phương thức được sử dụng. Đối với một phương thức cá thể, trình giám sát được liên kết với điều này (đối tượng mà phương thức được gọi) được sử dụng.


17
Hữu ích, tôi đã tìm kiếm trích dẫn đó +1
OscarRyz

80

Một điểm bạn phải cẩn thận (một số lập trình viên thường rơi vào cái bẫy đó) là không có liên kết giữa các phương thức tĩnh được đồng bộ hóa và các phương thức không tĩnh được đồng bộ hóa, tức là:

class A {
    static synchronized f() {...}
    synchronized g() {...}
}

Chủ yếu:

A a = new A();

Chủ đề 1:

A.f();

Chủ đề 2:

a.g();

f () và g () không được đồng bộ hóa với nhau và do đó có thể thực hiện hoàn toàn đồng thời.


18
nhưng nếu g () đang làm biến đổi một số biến tĩnh mà f () đang đọc. Làm thế nào để chúng ta làm cho chủ đề đó an toàn? Chúng ta rõ ràng có được một khóa trên lớp sau đó?
baskin

22
Vâng, phương pháp không tĩnh của bạn phải đồng bộ hóa một cách rõ ràng trên lớp đó (ví dụ, synchronized (MyClass.class) {...}.
jfpoilpret

@jfpoilpret "được đồng bộ hóa (MyClass. class) {...}" tương đương để làm cho phương thức này được đồng bộ hóa tĩnh, phải không?
crazymind

15

Trừ khi bạn thực hiện g () như sau:

g() {
    synchronized(getClass()) {
        ...
    }
}

Tôi thấy mẫu này cũng hữu ích khi tôi muốn thực hiện loại trừ lẫn nhau giữa các phiên bản khác nhau của đối tượng (ví dụ cần thiết khi tích lũy tài nguyên bên ngoài).


63
Lưu ý rằng thực sự có thể có một số lỗi rất tinh vi và khó chịu ở đây. Nhớ getClass()trả về kiểu thời gian chạy ; nếu bạn phân lớp lớp, thì lớp cha và lớp con sẽ đồng bộ hóa trên các khóa khác nhau. synchronized(MyClass.class)là cách để đi nếu bạn cần đảm bảo tất cả các trường hợp sử dụng cùng một khóa.
Cowan

4

Hãy xem trang tài liệu oracle về Khóa và đồng bộ hóa

Bạn có thể tự hỏi điều gì xảy ra khi một phương thức đồng bộ tĩnh được gọi, vì một phương thức tĩnh được liên kết với một lớp chứ không phải một đối tượng. Trong trường hợp này, luồng thu được khóa nội tại cho đối tượng Class được liên kết với lớp . Do đó, quyền truy cập vào các trường tĩnh của lớp được kiểm soát bởi một khóa khác với khóa đối với bất kỳ trường hợp nào của lớp .


2

Một phương thức tĩnh cũng có một đối tượng liên quan. Nó thuộc về tệp Class. Class trong bộ công cụ JDK. Khi tệp. Class tải vào ram, Class. Class tạo một thể hiện của nó được gọi là đối tượng mẫu.

Ví dụ: - khi bạn cố gắng tạo đối tượng từ lớp khách hàng hiện tại như

Customer c = new Customer();

Tải khách hàng. Lớp vào RAM. Trong thời điểm đó Class. Class trong bộ công cụ JDK tạo ra một đối tượng được gọi là đối tượng Mẫu và tải Khách hàng đó vào đối tượng khuôn mẫu đó. Các thành viên của Khách hàng đó trở thành các thuộc tính và phương thức trong đối tượng khuôn mẫu đó.

Vì vậy, một phương thức hoặc thuộc tính tĩnh cũng có một đối tượng


2

Các ví dụ dưới đây cho rõ ràng hơn giữa lớp và khóa đối tượng, hy vọng ví dụ dưới đây cũng sẽ giúp người khác :)

Ví dụ, chúng ta có các phương thức bên dưới một lớp thu nhận và khóa đối tượng thu nhận khác:

public class MultiThread {

    public static synchronized void staticLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public synchronized void objLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

Vì vậy, bây giờ chúng ta có thể có các kịch bản sau đây:

  1. Khi các luồng sử dụng cùng một Đối tượng cố gắng truy cập cùng một phương thức objLock OR staticLock (tức là cả hai luồng đang cố truy cập cùng một phương thức)

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
    
  2. Khi các luồng sử dụng cùng một Đối tượng cố gắng truy cập staticLockobjLockcác phương thức cùng một lúc (cố gắng truy cập các phương thức khác nhau)

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
    
  3. Khi các luồng sử dụng các đối tượng khác nhau cố gắng truy cập staticLockphương thức

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
    
  4. Khi các luồng sử dụng các đối tượng khác nhau cố gắng truy cập objLockphương thức

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
    

0

Đối với những người không quen thuộc với phương thức được đồng bộ hóa tĩnh bị khóa trên đối tượng lớp, ví dụ như đối với lớp chuỗi String. Class trong khi phương thức được đồng bộ hóa khóa trên đối tượng hiện tại của đối tượng được biểu thị bởi từ khóa này trong Java. Do cả hai đối tượng này khác nhau nên chúng có khóa khác nhau, vì vậy trong khi một luồng đang thực thi phương thức đồng bộ hóa tĩnh, thì luồng khác trong java không cần đợi luồng đó quay trở lại thay vào đó, nó sẽ thu được khóa riêng được ký hiệu là byte. Class bằng chữ và nhập vào phương pháp đồng bộ tĩnh.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.