2016-07-29 12 views
12

Nói chung tôi luôn thấy tài nguyên thử dùng để phân bổ đối tượng mới dụ có phương thức close() được gọi khi nó nằm ngoài phạm vi. Theo như tôi có thể nói, việc tạo một đối tượng mới không phải là một yêu cầu và cú pháp try-with-resources chỉ cần một biến cục bộ để gọi close() khi nó nằm ngoài phạm vi. Vì vậy, bạn có thể sử dụng nó để kiểm soát "hoạt động được ghép nối" chẳng hạn như phân bổ thứ gì đó từ một nhóm và đảm bảo nó được trả về.Có đang sử dụng tài nguyên cố gắng mà không có biểu mẫu xấu đối tượng mới không?

Ví dụ, MyHandle dưới đây cho thấy làm thế nào để phát hành một trường hợp gộp khi bạn không còn cần đến nó:

// init 
class MyHandle implements AutoCloseable { 
    boolean inUse = false; 
    public MyHandle allocate() { 
     inUse = true; 
     return this; 
    } 

    public void close() { 
     inUse = false; 
    } 
} 

MyHandle[] pool = new MyHandle[POOL_SIZE]; 
for (int i = 0; i < pool.length; i++) { 
    pool[i] = new MyHandle(i); 
} 

// allocate 
MyHandle allocateFromPool() { 
    for (int i = 0; i < pool.length; i++) { 
     if (!pool[i].inUse) 
      return pool[i].allocate(); 
    } 
    throw new Exception("pool depleted"); 
} 

// using resources from the pool 

try (MyHandle handle = allocateFromPool()) { 
    // do something 
} 
// at this point, inUse==false for that handle... 

Đây có phải là coi hình thức xấu?

EDIT: Tôi đoán tôi đang hỏi liệu có lựa chọn thay thế tốt hơn để xây dựng loại logic này hay không, hoặc có một số nhược điểm lớn khi đi theo phương pháp trên. Tôi thấy rằng việc sử dụng điều này trong thư viện làm cho một API sạch sẽ.

EDIT 2: Vui lòng bỏ qua các vấn đề trong ví dụ mã, tôi đã viết nội tuyến trong hộp văn bản SO để làm cho câu hỏi của tôi rõ ràng với một số loại ví dụ. Rõ ràng đó không phải là mã thực! :)

+5

Không sao - đó cũng thường là cách thực hiện khi sử dụng hồ bơi kết nối: 'try (Connection c = pool_or_datasource.getConnection()) {}' ... – assylias

Trả lời

10

Cú pháp thử-với-tài nguyên được dự định như một đường cú pháp để cho phép bạn đảm bảo bạn vứt bỏ một đối tượng, bất kể logic xử lý sẽ là gì. Trong trường hợp của bạn, nó trả về đối tượng cho hồ bơi. Hoàn toàn không có gì sai khi sử dụng try-with-resource như thế này. Nó có thể không phải là cách sử dụng phổ biến nhất cho nó, nhưng nó chắc chắn là một hợp lệ.

4

Dưới trang bìa, hầu hết các tài nguyên (ví dụ: Trình mô tả tệp) được phân bổ hiệu quả từ một hệ điều hành, sau đó quay lại hồ bơi khi đóng.

Sử dụng tài nguyên thử theo cách này là hoàn toàn hợp lệ.

N.B. ví dụ mã của bạn có vấn đề luồng đáng kể mặc dù, nhưng tôi cho rằng sự an toàn chủ đề cần thiết đã được loại bỏ để rõ ràng trong câu hỏi. Tôi đề cập đến nó chỉ vì mọi người KHÔNG nên sao chép mã của bạn và sử dụng nó trong khi thực hiện.

2

Không có gì sai với các tài nguyên cố gắng như vậy. Nhưng trong trường hợp của bạn, tôi sẽ lo lắng về việc tái sử dụng các xử lý đóng đã được mở lại từ một chủ đề khác.

Một chút hướng dẫn sẽ giải quyết được sự cố đó, trả lại MyHandleWrapper thay vì truy cập trực tiếp vào MyHandle (allocateFromPool sẽ trả lại phiên bản mới của MyHandleWrapper). Nó sẽ không! giải quyết tất cả các vấn đề luồng khác.

public class MyHandleWrapper extends MyHandle { 
    private MyHandle handle; 
    private boolean closed; 

    public void close() { 
     if(!closed){ 
      handle.inUse = false; 
     } 
     closed = true; 
    } 

    public void read() { 
     if (closed) { 
      throw new IllegalStateException("Already closed"); 
     } 
     handle.read(); 
    } 
} 

Về cơ bản, bạn giữ thông tin nếu tay cầm được đóng trong MyHandleWrapper. Bạn bảo vệ mọi trạng thái thay đổi quyền truy cập vào handle bằng cờ đó, nếu cần, hãy ném ngoại lệ thích hợp.

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