112

Nếu tôi đồng bộ hóa hai phương thức trên cùng một lớp, chúng có thể chạy đồng thời trên cùng một đối tượng không? ví dụ:

class A {
    public synchronized void methodA() {
        //method A
    }

    public synchronized void methodB() {
        // method B
    }
}

Tôi biết rằng tôi không thể chạy methodA()hai lần trên cùng một đối tượng trong hai luồng khác nhau. điều tương tự trong methodB().

Nhưng tôi có thể chạy methodB()trên các chủ đề khác nhau trong khi methodA()vẫn đang chạy? (cùng đối tượng)

|
113

Cả hai phương pháp khóa cùng một màn hình. Do đó, bạn không thể đồng thời thực thi chúng trên cùng một đối tượng từ các luồng khác nhau (một trong hai phương thức sẽ chặn cho đến khi kết thúc phương thức kia).

|
  • 1

    Tôi đã có thêm một câu hỏi này. Giả sử cả hai phương thức đều tĩnh, phương thứcA được gọi bằng Class trong khi phương thứcB được gọi bằng cách sử dụng đối tượng như A.methodA () trong t1 và obj.methodB () trong t2. Điều gì sẽ xảy ra bây giờ, họ sẽ chặn ????

    – Trịnh Thành An 12:16:45 21/03/2013
  • 1

    @ amod0017: obj.methodB()đồng nghĩa với A.methodB()khi methodB()static. Do đó, họ sẽ chặn (trên lớp, không phải của đối tượng, màn hình).

    – Hoàng Mỹ Yến 12:21:07 21/03/2013
  • 1

    sẽ cố gắng và lấy lại cho nó. :)

    – Tạ Minh Nhân 14:34:01 21/03/2013
  • 1

    @NPE Vì vậy, ngay cả khi cả hai phương thức là tĩnh và 2 luồng t1 và t2 trên cùng một đối tượng cố gắng gọi đồng thời phương thứcA () và phương thứcB () thì chỉ có luồng 1 (giả sử t1) sẽ thực thi và luồng khác phải đợi cho đến khi t1 giải phóng khóa ?

    – Ngô Hồng Nhật 21:15:50 03/05/2015
  • 1

    Hãy nhớ rằng các phương thức tĩnh sử dụng khóa trên .classđối tượng. Vì vậy, nếu bạn có class A {static synchronized void m() {} }. Và sau đó một luồng gọi new A().m()nó là khóa trên new A()đối tượng. Nếu sau đó, một luồng khác gọi A.m()nó là NHẬP PHƯƠNG PHÁP KHÔNG CÓ VẤN ĐỀ vì những gì nó tìm kiếm là khóa trên A.classđối tượng trong khi KHÔNG CÓ CẢM XÚC nào sở hữu loại khóa này . Vì vậy, mặc dù bạn đã khai báo phương thức synchronizednhưng thực tế IS được truy cập bởi hai luồng khác nhau TẠI THỜI GIAN . Do đó: không bao giờ sử dụng các tham chiếu đối tượng để gọi các phương thức tĩnh

    – Ngô Thiên Mạnh 08:02:12 19/10/2015
87

Trong ví dụ methodA và methodB là các phương thức cá thể (trái ngược với các phương thức tĩnh). Đưa synchronizedvào một phương thức cá thể có nghĩa là luồng phải thu được khóa ("khóa nội tại") trên đối tượng mà phương thức được gọi trước khi luồng có thể bắt đầu thực thi bất kỳ mã nào trong phương thức đó.

Nếu bạn có hai phương thức cá thể khác nhau được đánh dấu đồng bộ hóa và các luồng khác nhau đang gọi các phương thức đó đồng thời trên cùng một đối tượng, các luồng đó sẽ tranh nhau cho cùng một khóa. Khi một luồng được khóa, tất cả các luồng khác sẽ bị tắt khỏi tất cả các phương thức cá thể được đồng bộ hóa trên đối tượng đó.

Để hai phương thức chạy đồng thời, chúng sẽ phải sử dụng các khóa khác nhau, như thế này:

class A {
    private final Object lockA = new Object();
    private final Object lockB = new Object();

    public void methodA() {
        synchronized(lockA) {
            //method A
        }
    }

    public void methodB() {
        synchronized(lockB) {
            //method B
        }
    }
}

trong đó cú pháp khối được đồng bộ hóa cho phép chỉ định một đối tượng cụ thể mà luồng thực thi cần có khóa nội tại để vào khối.

Điều quan trọng cần hiểu là mặc dù chúng tôi đang đặt một từ khóa "đồng bộ hóa" cho các phương thức riêng lẻ, khái niệm cốt lõi là khóa nội tại đằng sau hậu trường.

Đây là cách hướng dẫn Java mô tả mối quan hệ:

Đồng bộ hóa được xây dựng xung quanh một thực thể nội bộ được gọi là khóa nội tại hoặc khóa màn hình. (Đặc tả API thường đề cập đến thực thể này đơn giản là "màn hình".) Khóa nội tại đóng vai trò trong cả hai khía cạnh của đồng bộ hóa: thực thi quyền truy cập độc quyền vào trạng thái của đối tượng và thiết lập các mối quan hệ trước khi cần thiết cho khả năng hiển thị.

Mỗi đối tượng có một khóa nội tại liên quan đến nó. Theo quy ước, một luồng cần truy cập độc quyền và nhất quán vào các trường của đối tượng phải có được khóa nội tại của đối tượng trước khi truy cập vào chúng, sau đó giải phóng khóa nội tại khi thực hiện với chúng. Một chủ đề được cho là sở hữu khóa nội tại giữa thời gian nó có được khóa và phát hành khóa. Miễn là một luồng sở hữu một khóa nội tại, không có luồng nào khác có thể có được cùng một khóa. Các luồng khác sẽ chặn khi nó cố gắng để có được khóa.

Mục đích của khóa là để bảo vệ dữ liệu chia sẻ. Bạn sẽ sử dụng các khóa riêng biệt như được hiển thị trong mã ví dụ ở trên chỉ khi mỗi khóa bảo vệ các thành viên dữ liệu khác nhau.

|
  • 1

    Vì vậy, trong ví dụ này, khóa nằm trên các đối tượng lockA \ lockB chứ không phải trên lớp A? Đây có phải là một ví dụ khóa cấp lớp ?

    – Trịnh Thành An 07:19:36 21/07/2016
  • 1

    @Nimrod: đó là khóa trên lockA và trên các đối tượng lockB chứ không phải trong trường hợp A. không có gì ở đây là khóa trên một lớp. Khóa cấp độ có nghĩa là có được khóa trên một đối tượng của lớp, bằng cách sử dụng một cái gì đó như static synchronizedhoặcsynchronized (A.class)

    – Hoàng Mỹ Yến 12:22:11 21/07/2016
  • 1

    Đây là liên kết đến hướng dẫn java giải thích chính xác những gì được trả lời ở đây.

    – Tạ Minh Nhân 17:46:17 09/11/2016
14

Java Thread thu được khóa cấp đối tượng khi nó nhập vào một phương thức java được đồng bộ hóa cá thể và có được khóa cấp độ lớp khi nó nhập vào phương thức java được đồng bộ hóa tĩnh .

Trong trường hợp của bạn, các phương thức (thể hiện) là cùng một lớp. Vì vậy, bất cứ khi nào một luồng nhập vào phương thức được đồng bộ hóa java hoặc chặn nó sẽ có được một khóa (đối tượng mà phương thức được gọi). Vì vậy, phương thức khác không thể được gọi cùng lúc trên cùng một đối tượng cho đến khi phương thức đầu tiên được hoàn thành và khóa (trên đối tượng) được giải phóng.

|
  • 1

    nếu tôi có hai luồng trên hai phiên bản khác nhau của lớp thì chúng sẽ có thể thực thi đồng thời cả hai phương thức sao cho một luồng gọi một phương thức được đồng bộ hóa và một luồng khác gọi phương thức được đồng bộ hóa thứ hai. Nếu sự hiểu biết của tôi là chính xác thì tôi có thể sử dụng private final Object lock = new object();với đồng bộ hóa để chỉ cho phép một luồng có thể thực thi một trong hai phương thức không? Cảm ơn

    – Hoàng Thùy Uyên 20:19:54 22/10/2018
10

Trong trường hợp của bạn, bạn đã đồng bộ hai phương thức trên cùng một thể hiện của lớp. Vì vậy, hai phương thức này không thể chạy đồng thời trên các luồng khác nhau của cùng một thể hiện của lớp A. Nhưng chúng có thể trên các thể hiện của lớp A khác nhau.

class A {
    public synchronized void methodA() {
        //method A
    }
}

giống như:

class A {
    public void methodA() {
        synchronized(this){
            // code of method A
        }
    }
}
|
  • 1

    Điều gì xảy ra nếu tôi định nghĩa một khóa như private final Object lock = new Object();và bây giờ sử dụng lockvới khối được đồng bộ hóa theo hai phương thức thì câu lệnh của bạn có đúng không? IMO vì Object là lớp cha của tất cả các đối tượng nên ngay cả khi các luồng nằm trong các thể hiện khác nhau của lớp, chỉ một người có thể truy cập mã bên trong khối được đồng bộ hóa tại một thời điểm. Cảm ơn.

    – Hieu Dao 20:16:27 22/10/2018
  • 1

    Nếu bạn định nghĩa "khóa đối tượng cuối cùng riêng tư" trong lớp và đồng bộ hóa với nó, bạn điền có khóa cho mỗi thể hiện của lớp, do đó, nó sẽ hoạt động giống như được đồng bộ hóa (điều này).

    – Hồ Kim Sa 23:51:56 07/11/2018
  • 1

    Có, Object là cha mẹ cho tất cả các lớp, nhưng trường hợp "khóa" trong trường hợp của bạn là "thể hiện trên mỗi lớp sở hữu", do đó, nó có tác dụng tương tự như "này" để đồng bộ hóa.

    – Ốc Bé 23:54:10 07/11/2018
7

Từ liên kết tài liệu oracle

Làm cho các phương thức được đồng bộ hóa có hai tác dụng:

Đầu tiên, 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ẽ. Khi một luồng đang thực thi một phương thức được đồng bộ hóa cho một đối tượng, tất cả các luồng khác gọi các phương thức được đồng bộ hóa cho cùng một khối đối tượng (tạm dừng thực thi) cho đến khi luồng đầu tiên được thực hiện với đối tượng.

Thứ hai, 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 khi có bất kỳ lời gọi tiếp theo nào của một phương thức đượ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 về trạng thái của đối tượng được hiển thị cho tất cả các luồng

Điều này sẽ trả lời câu hỏi của bạn: Trên cùng một đối tượng, Bạn không thể gọi phương thức được đồng bộ hóa thứ hai khi tiến hành thực hiện phương thức được đồng bộ hóa đầu tiên.

Hãy xem trang tài liệu này để hiểu các khóa nội tại và hành vi khóa.

|
5

Hãy nghĩ về mã của bạn như dưới đây:

class A {

public void methodA() {
    synchronized(this){        
      //method A body
    }
}

public void methodB() {
    synchronized(this){
      // method B body
    }
}

Vì vậy, được đồng bộ hóa ở mức phương thức đơn giản có nghĩa là đồng bộ hóa (điều này). nếu bất kỳ luồng nào chạy một phương thức của lớp này, nó sẽ có được khóa trước khi bắt đầu thực thi và giữ nó cho đến khi việc thực hiện phương thức kết thúc.

Nhưng tôi có thể chạy phương thứcB () trên các luồng khác nhau trong khi phương thứcA () vẫn đang chạy không? (cùng đối tượng)

Thật vậy, điều đó là không thể!

Do đó, nhiều luồng sẽ không thể chạy bất kỳ số lượng phương thức được đồng bộ hóa nào trên cùng một đối tượng.

|
  • 1

    Nếu tôi tạo Chủ đề trên hai đối tượng khác nhau của cùng một lớp thì sao? Trong trường hợp này Nếu tôi gọi một phương thức từ một luồng và phương thức khác từ luồng thứ hai thì chúng có được thực thi đồng thời không?

    – Trịnh Ngọc Thi 20:12:43 22/10/2018
  • 1

    Họ sẽ bởi vì họ là những đối tượng khác nhau. Đó là, nếu bạn muốn ngăn chặn nó, bạn có thể sử dụng các phương thức tĩnh và đồng bộ hóa lớp hoặc sử dụng một đối tượng biến lớp làm khóa hoặc tạo lớp Singleton. @Yug Singh

    – Bùi Quỳnh Mai 12:17:48 07/11/2018
4

Nói rõ hơn, có thể cả phương thức đồng bộ hóa tĩnh và không đồng bộ tĩnh đều có thể chạy đồng thời hoặc đồng thời vì một người đang có khóa cấp đối tượng và khóa cấp độ lớp khác.

|
1

Hai luồng khác nhau thực thi một phương thức được đồng bộ hóa chung trên một đối tượng, vì đối tượng giống nhau, khi một luồng sử dụng nó với phương thức được đồng bộ hóa, nó sẽ phải thay đổi khóa, nếu khóa được bật, luồng này sẽ chuyển sang trạng thái chờ, nếu khóa bị vô hiệu hóa thì nó có thể truy cập vào đối tượng, trong khi nó truy cập thì nó sẽ kích hoạt khóa và sẽ chỉ giải phóng khóa khi quá trình thực thi hoàn tất. Khi các luồng khác đến, nó sẽ thay đổi khóa, vì nó được kích hoạt, nó sẽ đợi cho đến khi luồng đầu tiên hoàn thành việc thực thi và giải phóng khóa được đặt trên đối tượng, khi khóa được giải phóng, luồng thứ hai sẽ có quyền truy cập vào đối tượng và nó sẽ cho phép khóa cho đến khi nó thực thi. vì vậy việc thực thi sẽ không đồng thời, cả hai luồng sẽ thực thi từng cái một,

|
1

Bạn đang đồng bộ hóa nó trên đối tượng không phải trên lớp. Vì vậy, họ không thể chạy đồng thời trên cùng một đối tượng

|
0

Các chính ý tưởng với đồng bộ hóa mà không chìm trong một cách dễ dàng là nó sẽ có hiệu lực chỉ khi phương pháp này được gọi là trên cùng một đối tượng dụ - nó đã được nhấn mạnh trong các câu trả lời và nhận xét -

Dưới đây chương trình mẫu là để xác định rõ ràng giống nhau -

public class Test {

public synchronized void methodA(String currentObjectName) throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA in");
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA out");
}

public synchronized void methodB(String currentObjectName)  throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB in");
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB out");
}

public static void main(String[] args){
    Test object1 = new Test();
    Test object2 = new Test();
    //passing object instances to the runnable to make calls later
    TestRunner runner = new TestRunner(object1,object2);
    // you need to start atleast two threads to properly see the behaviour
    Thread thread1 = new Thread(runner);
    thread1.start();
    Thread thread2 = new Thread(runner);
    thread2.start();
}
}

class TestRunner implements Runnable {
Test object1;
Test object2;

public TestRunner(Test h1,Test h2) {
    this.object1 = h1;
    this.object2 = h2;
}

@Override
public void run() {
    synchronizedEffectiveAsMethodsCalledOnSameObject(object1);
    //noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(object1,object2);
}

// this method calls the method A and B with same object instance object1 hence simultaneous NOT possible
private void synchronizedEffectiveAsMethodsCalledOnSameObject(Test object1) {
    try {
        object1.methodA("object1");
        object1.methodB("object1");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

// this method calls the method A and B with different object instances object1 and object2 hence simultaneous IS possible
private void noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(Test object1,Test object2) {
    try {
        object1.methodA("object1");
        object2.methodB("object2");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
}

Lưu ý sự khác biệt về đầu ra về cách cho phép truy cập đồng thời như mong đợi nếu các phương thức được gọi trên các thể hiện đối tượng khác nhau.

Ouput với noEffectOfSynyncizedAsMethodsCalledOnDifferentObjects () đã nhận xét - đầu ra theo thứ tự phương thứcA in> methodA Out .. methodB in> methodB Out

và Ouput với syncEffectiveAsMethodsCalledOnSameObject () đã nhận xét - đầu ra cho thấy quyền truy cập đồng thời của phương thứcA bởi Thread1 và Thread0 trong phần được tô sáng -

Tăng số lượng chủ đề sẽ làm cho nó thậm chí còn đáng chú ý hơn.

|
0

Không, điều đó là không thể, nếu có thể thì cả hai phương pháp có thể cập nhật cùng một biến đồng thời có thể dễ dàng làm hỏng dữ liệu.

|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.