2009-03-03 19 views
5

Tôi đang cố gắng tìm hiểu câu chuyện cơ bản của Semaphore trong vấn đề Ăn uống Triết học. Ngay bây giờ, tôi có một mảng của lớp Đũa, và mỗi Đũa có một semaphore với 1 giấy phép có sẵn:Các vấn đề về semaphore trong Java với các nhà triết học ăn uống

public class Chopstick 
{ 
    Thread holder = null; 
    private Semaphore lock = new Semaphore(1); 

    public synchronized void take() throws InterruptedException 
    { 
     this.lock.acquire(); 
     holder = Thread.currentThread(); 

    } 

    public synchronized void release() 
    { 
     this.lock.release(); 
     holder = null; 
    } 
} 

Biến giữ được sử dụng cho một chức năng mà tôi không chắc chắn tôi cần:

public synchronized void conditionalRelease() 
{ 
    if (holder == Thread.currentThread()) 
    { 
     holder = null; 
     this.lock.release(); 
    } 
} 

Chương trình biên dịch và chạy, nhưng dường như có một số rắc rối khi nhả đũa. Đôi khi, đôi đũa được thả ra, đôi khi chúng không có. Khi họ không phát hành, chương trình cuối cùng bị treo lên khi tất cả đũa được lấy và một nhà triết học đang đói.

Đây là mã trong lớp Triết gia để giải phóng đũa sau một khoảng thời gian ngẫu nhiên:

System.out.println(this.name + " is eating"); 
Thread.sleep(this.getRandTime()); 
System.out.println(this.name + " has finished eating"); 

rightChopstick.release(); 
System.out.println(this.name + " has released the right chopstick"); 
leftChopstick.release(); 
System.out.println(this.name + " has released the left chopstick"); 

chương trình của tôi không ra "Triết gia 0 đã ăn xong", ví dụ, và tiếp tục thực hiện. Hai dòng còn lại không bao giờ xuất ra, vì vậy rõ ràng có điều gì đó sai trái theo cách tôi đang phát hành.

Mọi trợ giúp đều được đánh giá cao.

Trả lời

8

Tôi sẽ lấy từ khóa 'đồng bộ' ra khỏi các chữ ký phương thức của bạn. Bạn đang sử dụng một cơ chế khóa bên ngoài (semaphore, trong trường hợp này). Từ khóa 'đồng bộ' đang cố gắng lấy khóa bằng cách sử dụng mutex của đối tượng. Bây giờ bạn đang khóa trên 2 tài nguyên mà tôi nghi ngờ có thể gây ra bế tắc.

+0

Hà! Đó là chính xác những gì nó đã được ... Tôi đã phải thực hiện hai cách khác nhau này cho một bài tập và tôi dán mã sao chép cho phương pháp đầu tiên và quên để loại bỏ các từ khóa đồng bộ. Nice tìm. –

1

Vấn đề là khi thread1 có một chiếc đũa cụ thể và cố gắng khác để nhận được cùng một nó sẽ chờ đợi trong take() -method trên dòng this.lock.acquire(); nhưng nó sẽ KHÔNG nhả màn hình trên đối tượng riêng của mình.

Nếu bây giờ thread1 cố gắng nhả đũa, nó không thể nhập release() -method vì nó vẫn bị khóa bởi luồng khác đang chờ trong take(). Đó là một bế tắc

1

Có vẻ như một chút khó hiểu rằng bạn vừa khóa trên đũa và giữ nó có kích thước semaphore 1. Nói chung một semaphore cung cấp vé cho một tài nguyên và nếu bạn chỉ có một vé, đó là loại trừ lẫn nhau có hiệu quả giống hệt với khóa (khối đồng bộ hoặc đối tượng Khóa). Bạn có thể xem xét thực sự làm cho các Chopstick các đối tượng khóa chính nó.

Tôi đã làm một bài đăng blog trên các nhà triết học ăn uống trong Java một thời gian trở lại nếu bạn quan tâm, mặc dù nó thực sự về cách tránh bế tắc bằng cách sử dụng các chiến lược khác.

+0

Có vẻ như đây là một phần của bài tập về nhà, nơi anh ta có một số yêu cầu nấu ăn nói rằng phải sử dụng các ẩn dụ. –

+0

Điều khác bạn có thể làm là thực sự có Chopstick mở rộng Semaphore (hoặc Lock). :) Mặc dù điều đó sẽ không mua cho bạn bất cứ điều gì hơn bằng cách sử dụng nó trực tiếp. –

0

Philospher cần để có được khóa trên cả chosticks trước khi bắt đầu ăn uống và đón sẽ leftone đầu tiên sau đó chờ cho đúng nên bắt đầu ăn vì vậy phương pháp bắt đầu nên được đồng bộ. phương pháp sau đây sẽ làm cho nó hoạt động:

public synchronized void startEating() { 
    leftChopstick.acquire(); 
    rightChopstick.acquire(); 
} 

public void finishEating(int id) { 
    leftChopstick.release(); 
    rightChopstick.release(); 
} 
1

Hãy chắc chắn rằng không có bất kỳ khóa hoặc từ khóa synchronized sử dụng. Các mã dưới đây cho các thanh chop hoạt động tốt cho tôi ..Không phải là một chuyên gia nhưng phải cung cấp cho u một số ý tưởng;

public class Chopstick { 
private boolean inuse; 
Semaphore sem; 

public Chopstick(){ 

    inuse = false; 
    sem = new Semaphore(1); 
} 
public void pickUp() 
{ 
    try 
    { 
     while(inuse) 
     { 
      try 
      { 
       sem.acquire(); 

      } 
      catch(InterruptedException e) {} 
     } 
     inuse = true; 
    }catch(Exception e){} 
} 
public void putDown() 
{ 
    try 
    { 
     inuse = false; 
     sem.release(); 

    } 
    catch (Exception e){} 
} 

}

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