スレッドローカルデータベース接続を使用する場合、スレッドが存在するときに接続を閉じる必要があります。
これは、呼び出し元のスレッドのrun()メソッドをオーバーライドできる場合にのみ実行できます。それでも素晴らしい解決策ではありません。終了時に、そのスレッドによって接続が開かれたことがあるかどうかはわかりません。
問題は実際にはもっと一般的です:スレッドが終了するときにスレッドローカルオブジェクトのファイナライズメソッドを呼び出すようにスレッドを強制する方法。
java 1.5のソースを調べたところ、スレッドローカルマップがnullに設定されていることがわかりました。これにより、最終的にガベージコレクションがfinalize()を呼び出すようになりますが、ガベージコレクターを頼りにしたくありません。
データベース接続を確実に閉じるには、次のオーバーライドが避けられないようです。
@Override
public void remove() {
get().release();
super.remove();
}
ここで、release()は、データベース接続が開かれている場合は、データベース接続を閉じます。しかし、スレッドがこのスレッドローカルを使用したことがあるかどうかはわかりません。get()がこのスレッドによって呼び出されたことがない場合は、ここでかなりの労力が無駄になります。ThreadLocal.initialValue()が呼び出され、このスレッドにマップが作成されます。
Thorbjørnのコメントによるさらなる説明と例:
java.lang.ThreadLocalは、スレッドにバインドされているオブジェクトのファクトリの一種です。このタイプには、オブジェクトのゲッターとファクトリメソッド(通常はユーザーが作成)があります。getterが呼び出されると、このスレッドによって以前に呼び出されたことがない場合にのみ、ファクトリメソッドが呼び出されます。
ThreadLocalを使用すると、開発者は、スレッドコードがサードパーティによって作成された場合でも、リソースをスレッドにバインドできます。
例: MyTypeというリソースタイプがあり、スレッドごとに1つだけにしたいとします。
usingクラスで定義します。
private static ThreadLocal<MyType> resourceFactory = new ThreadLocal<MyType>(){
@override
protected MyType initialValue(){
return new MyType();
}
}
このクラスのローカルコンテキストで使用します。
public void someMethod(){
MyType resource = resourceFactory.get();
resource.useResource();
}
get()は、呼び出し元のスレッドのライフサイクルで一度だけinitialValue( )を呼び出すことができます。その時点で、MyTypeのインスタンスがインスタンス化され、このスレッドにバインドされます。このスレッドによるget()の後続の呼び出しは、このオブジェクトを再度参照します。
典型的な使用例は、MyTypeがスレッドセーフでないtext / date/xmlフォーマッターである場合です。
しかし、そのようなフォーマッターは通常、解放または閉じる必要はありません。データベース接続は解放する必要があります。私はjava.lang.ThreadLocalを使用して、スレッドごとに1つのデータベース接続を確立しています。
私の見方では、java.lang.ThreadLocalはそのためにほぼ完璧です。呼び出し元のスレッドがサードパーティのアプリケーションに属している場合、リソースのクローズを保証する方法がないためです。
私はあなたの頭脳の従者が必要です:java.lang.ThreadLocalを拡張することによって、私はスレッドごとに1つのデータベース接続をバインドすることができました。これは、変更またはオーバーライドできないスレッドを含む排他的な使用法です。キャッチされない例外でスレッドが停止した場合に備えて、接続が確実に閉じられるようにしました。
通常のスレッド終了の場合、ガベージコレクターは接続を閉じます(MyTypeがfinalize()をオーバーライドするため)。実際には、それは非常に迅速に発生しますが、これは理想的ではありません。
もし私が自分のやり方を持っていたら、java.lang.ThreadLocalに別のメソッドがあったでしょう:
protected void release() throws Throwable {}
このメソッドがjava.lang.ThreadLocalに存在し、スレッドの終了/終了時にJVMによって呼び出された場合、それを自分でオーバーライドして、接続を閉じることができます(そして、償還者はZionに来たはずです)。
そのような方法がない場合、私は閉鎖を確認する別の方法を探しています。JVMガベージコレクションに依存しない方法。