如何强制 Java 线程关闭线程-本地数据库连接
使用线程本地数据库连接时,当线程存在时,需要关闭连接。
只有当我可以覆盖调用线程的run()方法时,我才能做到这一点。即使这不是一个很好的解决方案,因为在退出时,我不知道该线程是否曾经打开过连接。
问题实际上更普遍:如何强制线程在退出时调用线程本地对象的某个终结方法。
我查看了java 1.5的源代码,发现线程本地映射设置为null,这最终会导致垃圾回收调用finize(),但我不想指望垃圾回收器。
为了确保数据库连接已关闭,以下重写似乎是不可避免的:
@Override
public void remove() {
get().release();
super.remove();
}
其中 release() 关闭数据库连接(如果已打开)。但是我们不知道线程是否曾经使用过这个线程本地。如果 get() 从未被这个线程调用过,那么这里就浪费了大量精力:将调用 ThreadLocal.initialValue(),将在此线程上创建映射,等等。
根据Thorbjørn的评论进一步澄清和示例:
java.lang.ThreadLocal 是绑定到线程的对象的一种工厂类型。此类型具有对象的 getter 和工厂方法(通常由用户编写)。当调用 getter 时,仅当此线程以前从未调用过 factory 方法时,它才会调用该工厂方法。
使用 ThreadLocal 允许开发人员将资源绑定到线程,即使线程代码是由第三方编写的。
示例:假设我们有一个名为 MyType 的资源类型,并且我们希望每个线程有一个且只有一个。
在 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 是一些线程不安全的文本/日期/xml 格式化程序时。
但是这样的格式化程序通常不需要发布或关闭,数据库连接需要,我正在使用java.lang.ThreadLocal为每个线程有一个数据库连接。
在我看来,java.lang.ThreadLocal几乎是完美的。这几乎是因为,如果调用线程属于第三方应用程序,则无法保证资源关闭。
我需要你的大脑:通过扩展java.lang.ThreadLocal,我设法为每个线程绑定一个数据库连接,因为它是独占的用法 - 包括我无法修改或覆盖的线程。我设法确保连接被关闭,以防线程在未捕获的异常中死亡。
在正常线程退出的情况下,垃圾回收器将关闭连接(因为 MyType 覆盖了 finalize())。实际上,它发生得相当快,但这并不理想。
如果我有我的方式,java.lang.ThreadLocal上会有另一种方法:
protected void release() throws Throwable {}
如果此方法存在于java.lang.ThreadLocal上,在任何线程退出/死亡时由JVM调用,那么在我自己的覆盖中,我可以关闭我的连接(救赎者会来到锡安)。
在没有这种方法的情况下,我正在寻找另一种方法来确认闭包。一种不依赖于 JVM 垃圾回收的方法。