如何强制Java线程关闭线程本地数据库连接 [英] How to force a Java thread to close a thread-local database connection

查看:248
本文介绍了如何强制Java线程关闭线程本地数据库连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当使用线程本地数据库连接时,当线程存在时需要关闭连接。

When Using a thread-local database connection, closure of the connection is required when the thread exists.

这只能在我可以覆盖运行时执行( )调用线程的方法。即使这不是一个很好的解决方案,因为在退出时,我不知道该线程是否曾打开过连接。

This I can only do if I can override the run() method of the calling thread. Even that is not a great solution, since at time of exit, I don't know if a connection has ever been opened by that thread.

问题实际上是更一般:如何强制线程在线程本地对象退出时调用一些终结方法。

The problem is in fact more general: How to force a thread to call some finalisation method of a thread-local object when it exits.

我查看了java 1.5的源代码并发现线程本地映射设置为null,这最终会导致垃圾收集调用 finalize(),但我不想指望垃圾收集器。

I looked at the sources of java 1.5 and found that the thread local map is set to null, which will eventually cause the garbage collection to call finalize(), but I don't want to count on the garbage collector.

以下覆盖似乎是不可避免的,以确保数据库连接已关闭:

The following override seems inevitable to make sure that a database connection is closed:

@Override 
public void remove() {
    get().release(); 
    super.remove(); 
}

其中 release()关闭数据库连接,如果它被打开了。但我们不知道该线程是否曾使用过该线程本地。如果此线程从未调用过get(),那么这里的工作就相当浪费:将调用ThreadLocal.initialValue(),将在此线程上创建一个映射等。

where release() closes the database connection, if it has been opened. But we don't know if the thread has ever used this thread-local. If get() has never been called by this thread, then there's quite a waste of effort here: ThreadLocal.initialValue() will be called, a map will be created on this thread, etc.

-

根据Thorbjørn的评论进一步澄清和示例:

Further clarification and example as per Thorbjørn's comment:

java.lang.ThreadLocal 是一种绑定到线程的对象的工厂类型。此类型具有对象的getter和工厂方法(通常由用户编写)。当调用getter时,只有在此线程之前从未调用过它时才调用工厂方法。

java.lang.ThreadLocal is a type of factory for an object that is bound to a thread. This type has a getter for the object and a factory method (typically written by the user). When the getter is called it calls the factory method only if it has never been called before by this thread.

使用 ThreadLocal 允许开发人员即使线程代码是由第三方编写的,也将资源绑定到线程。

Using ThreadLocal allows a developer to bind a resource to a thread even if the thread code was written by a third party.

示例:
假设我们有一个名为 MyType的资源类型我们希望每个线程只有一个。

Example: Say we have a resource Type called MyType and we want to have one and only one of it per thread.

在using类中定义:
private static ThreadLocal resourceFactory = new ThreadLocal (){
@override
protected MyType initialValue(){
return new MyType();
}
}

Define in the using class: private static ThreadLocal resourceFactory = new ThreadLocal(){ @override protected MyType initialValue(){ return new MyType(); } }

在此类的本地环境中使用:
public void someMethod(){
MyType resource = resourceFactory.get();
resource.useResource();
}

Use in local context in this class: public void someMethod(){ MyType resource = resourceFactory.get(); resource.useResource(); }

get()只能在生命周期中调用 initialValue()一次调用线程。此时, MyType 的实例将被实例化并绑定到此线程。此线程对 get()的后续调用再次引用此对象。

get() can call initialValue() only once in the life cycle of the calling thread. At that point an instance of MyType gets instantiated and bound to this thread. Subsequent calls to get() by this thread refer again to this object.

经典用法示例是 MyType 是一些线程不安全的text / date / xml格式化程序。

The classic usage example is when MyType is some thread-unsafe text/date/xml formatter.

但是这些格式化程序通常不需要发布或关闭,数据库连接可以和我一起使用< b> java.lang.ThreadLocal 每个线程有一个数据库连接。

But such formatters usually don't need to be released or closed, database connections do and I am using java.lang.ThreadLocal to have a one database connection per thread.

我看到它的方式, java.lang.ThreadLocal 几乎是完美的。几乎是因为如果调用线程属于第三方应用程序,则无法保证资源的关闭。

The way I see it, java.lang.ThreadLocal is almost perfect for that. Almost because there's no way to guarantee closure of the resource if the calling thread belongs to a third party application.

我需要你的大脑绅士:通过扩展 java。 lang.ThreadLocal 我设法为每个线程绑定一个数据库连接,因为它是独占用途 - 包括我无法修改或覆盖的线程。我设法确保在线程因未捕获的异常而死的情况下关闭连接。

I need your brains squires: By extending java.lang.ThreadLocal I managed to bind one database connection for every thread, for it's exclusive usage - including threads that I can not modify or override. I managed to make sure that the connections get closed in case the thread dies on uncaught exception.

在正常线程退出的情况下,垃圾收集器关闭连接(因为< b> MyType 覆盖 finalize())。实际上它发生得非常快,但这并不理想。

In case of normal thread exit, the garbage collector closes the connection (because MyType overrides the finalize()). In actual fact it happens quite quickly, but this is not ideal.

如果我按照自己的方式行事,那么 java.lang上会有另一种方法。 ThreadLocal

If I had my way, there would have been another method on the java.lang.ThreadLocal:

protected void release() throws Throwable {}

如果此方法存在于 java.lang.ThreadLocal ,由JVM在任何线程退出/死亡时调用,那么在我自己的覆盖它我可以关闭我的连接(救赎者会来到锡安)。

If this method existed on java.lang.ThreadLocal, called by JVM upon any thread exit/death, then in my own override of it I could close my connection (and the redeemer would have come to Zion).

如果没有这种方法,我正在寻找另一种方法来确认关闭。一种不依赖于JVM垃圾回收的方式。

In the absence of such method, I'm looking for another way to confirm closure. A way that won't rely on the JVM garbage collection.

谢谢

推荐答案

如果你是一个敏感的性格,现在就把目光移开。

If you are of a sensitive disposition, look away now.

我不希望这种情况能够很好地扩展;它有效地使系统中的线程数加倍。可能有一些用例可以接受。

I wouldn't expect this to scale very well; it effectively doubles the number of threads in the system. There may be some use cases where it is acceptable.

public class Estragon {
  public static class Vladimir {
    Vladimir() { System.out.println("Open"); }
    public void close() { System.out.println("Close");}
  }

  private static ThreadLocal<Vladimir> HOLDER = new ThreadLocal<Vladimir>() {
    @Override protected Vladimir initialValue() {
      return createResource();
    }
  };

  private static Vladimir createResource() {
    final Vladimir resource = new Vladimir();
    final Thread godot = Thread.currentThread();
    new Thread() {
      @Override public void run() {
        try {
          godot.join();
        } catch (InterruptedException e) {
          // thread dying; ignore
        } finally {
          resource.close();
        }
      }
    }.start();
    return resource;
  }

  public static Vladimir getResource() {
    return HOLDER.get();
  }
}

更好的错误处理等等留作练习对于实现者。

Better error handling and so on is left as an exercise for the implementer.

您还可以查看使用另一个线程跟踪 ConcurrentHashMap 中的线程/资源轮询 isAlive 。但是这种解决方案是绝望的最后手段 - 对象可能最终会经常被检查或者很少被检查。

You could also have a look at tracking the threads/resources in a ConcurrentHashMap with another thread polling isAlive. But that solution is the last resort of the desperate - objects will probably end up being checked too often or too seldom.

我想不出任何其他的东西涉及仪器。 AOP可能有用。

I can't think of anything else that doesn't involve instrumentation. AOP might work.

连接池将是我最喜欢的选项。

Connection pooling would be my favoured option.

这篇关于如何强制Java线程关闭线程本地数据库连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆