2016-07-29 7 views
12

私はいつもリソースを試してみたが、新しいオブジェクトclose()メソッドがスコープ外になると呼び出されるように割り当てられていました。try-with-resourcesを新しいオブジェクトインスタンスの悪いフォームなしで使用していますか?

私が知る限り、新しいオブジェクトの作成は必須ではなく、try-with-resources構文では、範囲外になるとclose()を呼び出すためのローカル変数が必要です。したがって、プールから何かを割り当てたり、返されたものがあるかどうかを確認するなど、 "ペアオペレーション"を制御することができます。例えば

、以下MyHandleは、あなたが不要になったプールされたインスタンスを解放する方法を示しています。

// 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... 

が、このみなさ悪いフォームですか?

編集:私は、このようなロジックを構築するためのより良い選択肢があるかどうか、または上記のアプローチに進むときにいくつかの大きな欠点があるかどうか尋ねています。ライブラリでこれを使用すると、きれいなAPIが得られることがわかります。

EDIT 2:コード例の問題を無視して、私はSOテキストボックスにインラインで書いて、いくつかの例で質問を明確にしています。明らかにそれは実際のコードではありません! :)

+5

接続プールを使用すると、一般的にどのように処理されるのですか: 'try(Connection c = pool_or_datasource.getConnection()){}' ... – assylias

答えて

10

try-with-resource構文は、処分ロジックがどんなものであっても、オブジェクトを確実に処分できるようにするための構文的寛容を意図しています。あなたの場合、オブジェクトをプールに戻しています。このようなtry-with-resourceの使用には何の問題もありません。それはそれのための最も一般的な用途ではないかもしれませんが、間違いなく有効なものです。

4

ほとんどのリソース(ファイル記述子など)は、オペレーティングシステムによってプールから効果的に割り当てられ、閉じられるとプールに戻されます。

このようにtry-with-resourcesを使用することは完全に有効です。

N.B.あなたのコード例にはかなりのスレッド問題がありますが、質問の明確さのために必要なスレッドの安全性が削除されていると仮定します。私はそれを言います。なぜなら、人々はコードをコピーして実装で使用すべきではないからです。

2

このようなtry-with-resourcesでは何も問題ありません。しかし、あなたのケースでは、私は別のスレッドから再オープンされたクローズドハンドルを再利用することについての安全を心配します。

小さなインダイレクションでこの問題を解決するには、MyHandleに直接アクセスする代わりにMyHandleWrapperを返します(allocateFromPoolはMyHandleWrapperの新しいインスタンスを返します)。それはではありません!は他のすべてのスレッドの問題を解決します。

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(); 
    } 
} 

ハンドルがMyHandleWrapperで閉じられている場合は、基本的に情報を保持します。必要ならば、適切な例外をスローして、そのフラグを使用してhandleへのアクセスを変更するすべての状態を保護します。

関連する問題