2010-10-04 41 views
11

Vấn đề của tôi: Tôi có mạng không dây 802.15.4 được kết nối với cổng nối tiếp (sử dụng trình bao bọc). Tôi có thể gửi các gói vào mạng và lắng nghe các gói đến. Như bạn có thể tưởng tượng điều này là không đồng bộ cao.Cách tốt nhất để đồng bộ hóa tác vụ không đồng bộ

Ở đây có nhiệm vụ: Tôi muốn gửi lệnh đến mạng và chờ phản hồi trong một cuộc gọi chức năng. Ví dụ: Tôi muốn nhận được nhiệt độ từ Node với ID mạng 1338.

double getTemperature(int id) throws Exception { .... } 

Có cách nào tốt hơn chờ đợi cho một tin nhắn trả lời khác hơn là làm tất cả điều này "synchonized (object) chờ đợi (..) thông báo (..) "công cụ?

Trân trọng, bigbohne

Có lẽ thêm một số gia vị:

này nên tất cả kết thúc trong một webinterface nơi người dùng có thể yêu cầu các lệnh (hoặc thông qua ajax hoặc trực tiếp). Tôi cũng đã nghĩ về việc đệm các giá trị phản hồi trong cơ sở dữ liệu. Nhưng đối với một số lệnh, bạn NHẠC có câu trả lời trực tiếp về thành công/thất bại

+0

OK. Câu hỏi này điểm nhiều hơn theo hướng "có một số mẹo java mát mẻ giải quyết vấn đề này?" – Bigbohne

+0

Cái này cũng mát mẻ –

Trả lời

7

Bạn có thể thực hiện việc này với BlockingQueue để bạn không phải quản lý thủ công bất kỳ việc đồng bộ hóa nào. Yêu cầu có thể gửi tin nhắn, sau đó gọi take() trên BlockingQueue sẽ đợi phần tử hiển thị. Phần tử là phần trả lời được chèn vào hàng đợi bởi bất kỳ trình lắng nghe nào bạn có trên cổng khi trả lời được trả về.

Bạn chỉ cần phối hợp để người nghe và người yêu cầu có cùng một hàng đợi. Bạn chỉ cần một hàng đợi kích thước một cho mỗi yêu cầu để hỗ trợ kịch bản này.

// Send method 
BlockingQueue<Reply> q = new ArrayBlockingQueue<Reply>(1); 
serialCom.registerQueue(myRequest.getId()); 
serialCom.sendRequest(myRequest); 
return q.take(); 

//Listener 
BlockingQueue<Reply> q = queueMap.get(incomingMessage.getId()); 
q.add(incomingMessage.getReply()); 
+0

Đó chính xác là "Đặc biệt Java Thingy" Tôi đã tìm kiếm! – Bigbohne

1

Cách tốt hơn là kết hợp nó trong một số lớp yêu cầu/phản hồi có thể tái sử dụng. Bằng cách này bạn có thể có một cách tiêu chuẩn để truy vấn cổng nối tiếp và chờ phản hồi. Lớp này, tuy nhiên, chắc chắn sẽ phải sử dụng các từ khóa đồng bộ và chờ đợi và thông báo cho các lệnh một nơi nào đó trong việc thực hiện nó. Đây là một phần quan trọng trong việc viết Java và điều quan trọng là phải hiểu cách chúng hoạt động.

Nếu bạn thiết kế một chức năng như bạn nói, bạn phải đảm bảo rằng bạn gọi nó từ một chuỗi có thể chặn kết quả chờ đợi. Chức năng sẽ phải thực hiện một số loại vòng lặp chờ đợi bên trong nó chờ phản hồi từ cổng nối tiếp. Vì vậy, điều quan trọng là bất kỳ chủ đề nào đang chạy cũng có thể chờ đợi.

Điều này cũng mang lại một điểm bổ sung. Nếu bạn có nhiều luồng làm việc này, bạn sẽ cần phải có một số lớp xử lý giao tiếp cổng nối tiếp có thể xử lý nhiều yêu cầu đến từ nhiều luồng và xếp hàng chúng khi cần thiết để xử lý bản chất không đồng bộ của cổng nối tiếp và thiết bị cụ thể mà bạn đang kết nối. Ví dụ, nó có thể không thích hợp để gửi một lệnh thứ hai trước khi phản hồi từ đầu tiên được đọc hoàn toàn.

Có một số vấn đề phức tạp ở đây và điều quan trọng là phải có thiết kế phù hợp để giải quyết chúng một cách hợp lý.

+0

Cảm ơn bạn đã nhập. Điều này đưa tôi trở lại bút và giấy :) – Bigbohne

2

Tôi không chắc mình hiểu câu hỏi một cách chính xác, nhưng tôi thường sử dụng một số Future<T> cho các loại tác vụ này.

Nội bộ Future<T> sử dụng thực hiện chờ và thông báo và tất cả điều đó, nhưng giao diện chính nó trở nên khá sạch sẽ.

Future<Double> getTemperature(int id); 

Trong mã giao tiếp của bạn, bạn có thể ánh xạ thư đến với tương lai chưa được thực hiện. Nếu việc đặt hàng được đảm bảo, bạn có thể làm điều gì đó như

class Something { 
    Map<Integer, Queue<Object>> requests; 

    synchronized Future<?> request(int id, Object data) { 
     MyFutureImpl future = new MyFuture(); 
     requests.get(id).add(future); 
     serializeAndSend(id, data); 
     return future; 
    } 

    void serializeAndSend(id, data) {...} 

    synchronized void response(int id, Object data) { 
     MyFutureImpl future = requests.get(id).remove(); 
     future.setValue(data); // This would fulfill the future, and any 
           // threads waiting in a get() will get the 
           // value and continue. 
    } 
} 

Trường hợp MyFutureImpl là một triển khai cơ bản trong tương lai. Tôi giả sử có một chuỗi giao tiếp gọi số response() khi nhận được gói.Tôi cũng giả định rằng các serializeAndSend()-chức năng xử lý các văn bản cho khách hàng hoặc khối cho đến khi các hoạt động ghi có thể được thực hiện hoặc bàn giao cho một chủ đề giao tiếp.

Việc sử dụng cấu trúc bản đồ và xếp hàng có khả năng tương tranh có thể làm cho một số không cần thiết là synchronization. Nếu chỉ có một cuộc gọi xuất sắc cho mỗi id, thì Hàng đợi sẽ trở thành không cần thiết.

+0

Cảm ơn bạn đã cho ý tưởng của bạn. sẽ phải đi qua mã số của bạn – Bigbohne

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