2011-10-20 24 views

Trả lời

8

Sử dụng synchronized chỉ có thể truy cập một phương thức/khối chỉ trên chuỗi tại một thời điểm. Vì vậy, có, đó là chủ đề an toàn.

Hai khái niệm được kết hợp, chứ không phải loại trừ lẫn nhau. Khi bạn sử dụng wait(), bạn cần sở hữu màn hình trên đối tượng đó. Vì vậy, bạn cần phải có synchronized(..) trên đó trước đó. Sử dụng .wait() làm cho luồng hiện tại dừng lại cho đến khi một luồng khác gọi .notify() trên đối tượng mà nó đợi. Đây là một bổ sung cho synchronized, mà chỉ đảm bảo rằng chỉ có một chủ đề sẽ nhập một khối/phương pháp.

+0

vậy tại sao chúng ta cần sử dụng chờ đợi/thông báo cho các phương pháp? phải có một số khác biệt, phải không? – Alan

+0

xem cập nhật .... – Bozho

+1

Tôi nghĩ khi khối đồng bộ kết thúc, nó sẽ giải phóng khóa. Chủ đề khác thực thi phương thức hoặc câu lệnh đã đồng bộ sẽ chặn khi nó không thể lấy khóa. Nó cũng hoạt động như một cơ chế wait() notify(), rất giống nhau. Alan đang hỏi sự khác biệt của việc chờ() và thông báo() so với kết thúc khối đồng bộ thông thường là gì. –

2

Mục Java hiệu quả 69: "Do khó khăn khi sử dụng chờ và thông báo chính xác, bạn nên sử dụng các tiện ích tương thích cấp cao hơn thay vì".

Tránh sử dụng wait() và thông báo(): sử dụng synchronized hoặc các tiện ích khác từ java.util.concurrent, nếu có thể.

5

vì vậy sau khi bị xấu hổ trong một câu hỏi phỏng vấn về điều này, tôi quyết định tìm kiếm nó và hiểu nó một lần nữa cho 1 tỷ lần lol.

khối đồng bộ làm cho chuỗi mã an toàn. Không nghi ngờ gì về điều đó. Khi wait() và thông báo() hoặc notifyAll() đến là nơi bạn đang cố viết mã hiệu quả hơn. Ví dụ nếu bạn có một danh sách các mục mà nhiều chủ đề chia sẻ sau đó nếu u đặt nó trong khối đồng bộ của một màn hình sau đó đề đề sẽ liên tục nhảy vào và chạy mã qua lại, trở lại và pháo đài trong bối cảnh chuyển mạch ..... .even với một danh sách trống! Do đó, wait() được sử dụng trên màn hình (đối tượng bên trong đồng bộ (..)) như là một cơ chế để báo cho tất cả các luồng làm lạnh và ngừng sử dụng chu kỳ CPU cho đến khi có thông báo mới hoặc thông báoAll().

nên cái gì như:

synchronized(monitor) { 

    if(list.isEmpty()) 
     monitor.wait(); 
} 


...somewhere else... 

synchronized(monitor){ 

    list.add(stuff); 
    monitor.notifyAll(); 

} 
+0

Chính tả là bạn luôn gọi wait() trong vòng lặp, ví dụ: while (list.isEmpty()) monitor.wait() nếu bạn muốn đợi cho đến khi thực sự có cái gì đó được đặt trong danh sách bởi một luồng khác. https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#wait() – Arthur

+0

Đây phải là câu trả lời. Lập trình viên không thể chọn khối đồng bộ nào nên đi trước. Nhưng chờ đợi/thông báo có thể hướng dẫn khối nào nên đi trước. +1. –

0

khối đồng bộ được sử dụng, nếu 2 chủ đề của "cùng đối tượng" cố gắng accquire khóa. Kể từ khi lớp đối tượng giữ khóa, nó biết ai để cung cấp cho. Trong khi đó, nếu 2 chủ đề (nói t2 và t4) của 2 đối tượng (t1 & t2 của obj1 và t3 & t4 của obj 2) cố gắng lấy khóa, obj1 sẽ không biết khóa obj2 và obj2 sẽ không biết khóa obj1 . Do đó phương thức chờ và thông báo được sử dụng.

ví dụ:

//example of java synchronized method 
class Table{ 
synchronized void printTable(int n){//synchronized method 
    for(int i=1;i<=5;i++){ 
    System.out.println(n*i); 
    try{ 
     Thread.sleep(400); 
    }catch(Exception e){System.out.println(e);} 
    } 

} 
} 

class MyThread1 extends Thread{ 
Table t; 
MyThread1(Table t){ 
this.t=t; 
} 
public void run(){ 
t.printTable(5); 
} 

} 
class MyThread2 extends Thread{ 
Table t; 
MyThread2(Table t){ 
this.t=t; 
} 
public void run(){ 
t.printTable(100); 
} 
} 

public class TestSynchronization2{ 
public static void main(String args[]){ 
Table obj = new Table();//only one object 
MyThread1 t1=new MyThread1(obj); 
MyThread2 t2=new MyThread2(obj); 
t1.start(); 
t2.start(); 
} 
} 

Hai bài t1 và t2 thuộc về cùng một đối tượng, do đó đồng bộ hóa hoạt động tốt ở đây. Trong khi đó,

class Table{ 
synchronized void printTable(int n){//synchronized method 
    for(int i=1;i<=5;i++){ 
    System.out.println(n*i); 
    try{ 
     Thread.sleep(400); 
    }catch(Exception e){System.out.println(e);} 
    } 

} 
} 

class MyThread1 extends Thread{ 
Table t; 
MyThread1(Table t){ 
this.t=t; 
} 
public void run(){ 
t.printTable(5); 
} 

} 
class MyThread2 extends Thread{ 
Table t; 
MyThread2(Table t){ 
this.t=t; 
} 
public void run(){ 
t.printTable(100); 
} 
} 

public class TestSynchronization2{ 
public static void main(String args[]){ 
Table obj = new Table(); 
Table obj1 = new Table(); 
MyThread1 t1=new MyThread1(obj); 
MyThread2 t2=new MyThread2(obj1); 
t1.start(); 
t2.start(); 
} 
} 

Khi bạn chạy chương trình trên, đồng bộ hóa không hoạt động vì mỗi chủ đề thuộc về đối tượng khác nhau, Do đó bạn nên sử dụng chờ đợi và thông báo ở đây.

0

chờ/thông báo là bắt buộc khi bạn muốn đợi một số điều kiện (ví dụ:đầu vào của người dùng) INSIDE khối được đồng bộ hóa.

sử dụng tiêu biểu:

synchronized(obj) { 
    // do something 

    while(some condition is not met) { 
     obj.wait(); 
    } 
    // do something other 
} 

Giả sử rằng bạn không sử dụng wait(). Sau đó, bạn phải thực hiện vòng lặp bận rộn bỏ phiếu điều kiện mà bạn muốn, đó là xấu cho hiệu suất.

synchronized(obj) { 
    // do something 

    while(some condition is not met) { // busy loop } 

    // do something other 
} 

Lưu ý quan trọng: Mặc dù một sợi được đánh thức bởi thông báo() hoặc notifyAll() từ thread khác, thread thức tỉnh không KHÔNG đảm bảo để ngay lập tức tiếp tục thực hiện của nó. Nếu có các luồng khác đang đợi để thực hiện một khối đồng bộ trên cùng một đối tượng, thì luồng được đánh thức phải cạnh tranh với các luồng.

+0

Tôi không chắc đây là một ví dụ hay. wait() là một phương thức chặn, vì vậy nó không phải nằm trong một vòng lặp vô hạn. Bạn chỉ có thể sử dụng wait() trong một khối đồng bộ, và khi điều kiện của bạn được đáp ứng, bạn có thể sử dụng notify() trong một khối được đồng bộ khác để "bỏ chặn" phương thức wait(). – Scarfe

1

Làm phương pháp như synchronized có hai tác dụng:

Thứ nhất, nó không phải là có thể cho hai lời gọi của phương pháp đồng bộ trên cùng một đối tượng để interleave. Khi một luồng đang thực hiện 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 ra các phương thức đồng bộ cho cùng một khối đối tượng (đình chỉ thực hiện) cho đến khi chuỗi đầu tiên được thực hiện với đối tượng

Thứ hai, khi thoát khỏi phương thức đồng bộ , nó sẽ tự động thiết lập mối quan hệ xảy ra trước đó với 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 đối với trạng thái của đối tượng được hiển thị cho tất cả các luồng.

đồng bộ hóa giúp bạn bảo vệ mã quan trọng.

Nếu bạn muốn thiết lập liên lạc giữa nhiều chủ đề, bạn phải sử dụng wait()notify()/notifyAll()

wait(): Nguyên nhân xử lí hiện tại để chờ cho đến khi thread khác gọi phương thức notify() hoặc phương pháp notifyAll() cho đối tượng này.

notify(): Đánh thức một chuỗi đang chờ trên màn hình của đối tượng này. Nếu bất kỳ chủ đề nào đang chờ đối tượng này, một trong số chúng được chọn để được đánh thức.

notifyAll(): Đánh thức tất cả các chuỗi đang chờ trên màn hình của đối tượng này. Một chuỗi chờ trên màn hình của đối tượng bằng cách gọi một trong các phương thức chờ.

Trường hợp sử dụng đơn giản để sử dụng wait() và thông báo(): Vấn đề về nhà sản xuất và người tiêu dùng.

Chủ đề người tiêu dùng phải đợi cho đến khi Chuỗi nhà sản xuất tạo dữ liệu. wait() và notify() có ích trong kịch bản trên. Trong một khoảng thời gian, các lựa chọn thay thế tốt hơn đã được giới thiệu. Tham khảo trang hướng dẫn này high level concurrency.

Trong thuật ngữ đơn giản:

Sử dụng synchronized để bảo vệ bảo vệ phần quan trọng của dữ liệu của bạn và bảo vệ mã của bạn.

Sử dụng wait()notify() cùng với đồng bộ hóa nếu bạn muốn thiết lập liên lạc giữa nhiều chủ đề một cách an toàn, phụ thuộc lẫn nhau vào nhau.

liên quan SE câu hỏi:

What does 'synchronized' mean?

A simple scenario using wait() and notify() in java

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