Java スレッドにスレッドローカルのデータベース接続を強制的に閉じる方法

StackOverflow https://stackoverflow.com/questions/1700212

質問

スレッドローカルデータベース接続を使用する場合、スレッドが存在する場合は接続を閉じる必要があります。

これは、呼び出しスレッドの run() メソッドをオーバーライドできる場合にのみ実行できます。終了時には、そのスレッドによって接続が開かれたかどうかがわからないため、これでも優れた解決策とは言えません。

実際、問題はより一般的なものです。スレッドが終了するときにスレッドローカル オブジェクトの何らかの終了メソッドを呼び出すように強制する方法。

Java 1.5 のソースを調べたところ、スレッドのローカル マップが null に設定されており、最終的にガベージ コレクションが呼び出されることがわかりました。 ファイナライズ(), 、しかしガベージコレクターには頼りたくない。

データベース接続を確実に閉じるには、次のオーバーライドが避けられないようです。

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

どこ リリース() データベース接続が開いている場合は、データベース接続を閉じます。ただし、スレッドがこのスレッドローカルを使用したことがあるかどうかはわかりません。get() がこのスレッドによって一度も呼び出されなかった場合、ここでの労力はかなり無駄になります。 ThreadLocal.initialValue() が呼び出されたり、このスレッドにマップが作成されたりします。

-

Thorbjørn のコメントによるさらなる説明と例:

java.lang.ThreadLocal スレッドにバインドされたオブジェクトのファクトリのタイプです。この型には、オブジェクトのゲッターとファクトリ メソッド (通常はユーザーが作成したメソッド) があります。ゲッターが呼び出されると、このスレッドによって以前に呼び出されたことがない場合にのみ、ファクトリ メソッドが呼び出されます。

使用する スレッドローカル 開発者は、スレッド コードがサードパーティによって作成されたものであっても、リソースをスレッドにバインドできます。

例:というリソースタイプがあるとします。 私のタイプ そして、スレッドごとに 1 つだけを持つ必要があります。

使用するクラスで次のように定義します。private stathic threadlocal resourceFactory = new threadlocal(){@Override Protected myType initialValue(){return new myType();}}

このクラスのローカル コンテキストで使用します。public void somemethod(){mytype resource = resourceFactory.get();resource.useResource();}

得る() 呼び出すことができます 初期値() 呼び出し側スレッドのライフサイクルで 1 回だけ。その時点で、 私のタイプ インスタンス化され、このスレッドにバインドされます。以降の呼び出し 得る() このスレッドでこのオブジェクトを再度参照してください。

典型的な使用例は次のような場合です。 私のタイプ スレッドセーフではないテキスト/日付/xml フォーマッタです。

しかし、そのようなフォーマッタは通常、解放したり閉じたりする必要はなく、データベース接続は解放したり閉じたりする必要があり、私はそれを使用しています java.lang.ThreadLocal スレッドごとに 1 つのデータベース接続を確立します。

私の見立てでは、 java.lang.ThreadLocal それに関してはほぼ完璧です。呼び出し元のスレッドがサードパーティのアプリケーションに属している場合、リソースを確実に閉じる方法がないからです。

あなたの頭脳の従者が必要です:延長することで java.lang.ThreadLocal 変更またはオーバーライドできないスレッドを含め、排他的に使用するため、スレッドごとに 1 つのデータベース接続をバインドすることができました。例外がキャッチされずにスレッドが終了した場合に備えて、接続が確実に閉じられるようにすることができました。

通常のスレッド終了の場合、ガベージ コレクターは接続を閉じます。 私のタイプ をオーバーライドします ファイナライズ())。実際には、これは非常に早く起こりますが、これは理想的ではありません。

私のやり方があれば、別の方法があったでしょう java.lang.ThreadLocal:

protected void release() throws Throwable {}

このメソッドが存在していれば java.lang.ThreadLocal, 、スレッドの終了/停止時に JVM によって呼び出され、それを自分でオーバーライドすることで接続を閉じることができます (そして、償還者は Zion に来るでしょう)。

そのような方法がないので、閉鎖を確認する別の方法を探しています。JVM ガベージ コレクションに依存しない方法。

ありがとう

役に立ちましたか?

解決

あなたは敏感な処分である場合は、

、今離れて見ます。

私は、これは非常にうまくスケールするために期待していません。それが効果的にシステム内のスレッドの数が2倍になります。それが許容され、いくつかのユースケースがあるかもしれません。

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

より良いエラー処理など実装のための課題として残されています。

また、別のスレッドのポーリングとConcurrentHashMap内のスレッド/リソースの追跡を見ている可能性<のhref = "http://java.sun.com/javase/6/docs/api/java/lang/Thread .htmlを#のisAlive()」のrel = "noreferrer">のisAlive を。しかし、そのソリューションは、必死の最後の手段である - オブジェクトは、おそらくあまりにも多くの場合、またはあまりにもめったにチェックされてしまいます。

私は機器を必要としない何かを考えることはできません。 AOPが動作する可能性があります。

接続プールは私の好む選択肢となります。

他のヒント

タグで新しいRunnableをして、あなたのRunnableをラップ
try {
  wrappedRunnable.run();
} finally {
  doMandatoryStuff();
}

建設、そしてそれが代わりに実行させます。

あなたも、メソッドにそれを作ることができ、例:

  Runnable closingRunnable(Runnable wrappedRunnable) {
    return new Runnable() {
      @Override
      public void run() {
        try {
          wrappedRunnable.run();
        } finally {
          doMandatoryStuff();
        }
      }
    };
  }

と、あなたが探している実行可能に渡してそのメソッドを呼び出します。

また、代わりに、エグゼキュータを使用して検討する必要があります。それははるかに簡単Runableと呼び出し可能オブジェクトを管理することができます。

あなたがExecutorServiceのを使用する場合、あなたはexecutor.submit(closingRunnable(normalRunnable))のようにそれを使用することができます。

あなたがあなたの全体のExecutorServiceのシャットダウンすることがありますことを知っているとの接続はその時点で終了したい場合は、

、あなたは「すべてのタスクが実行者に呼びかけ行われ、シャットダウンされた後、」また、近くにないスレッドファクトリを設定することができ、例:

  ExecutorService autoClosingThreadPool(int numThreads) {
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(numThreads, numThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); // same as Executors.newFixedThreadPool
    threadPool.setThreadFactory(new ThreadFactory() {
      @Override
      public Thread newThread(Runnable r) {
        return new Thread(closingRunnable(r)); // closes it when executor is shutdown
      }
    });
    return threadPool;
  }

doMandatoryStuffは、接続がこれまでに開かれたか否かを知ることができるかどうか事前に、頭に浮かぶ一つのことは、それが(開かれたかどうかだけ追跡する第二のThreadLocalを持っているかどうかという点で例:接続があるとき開かれ、その後、

)...クリーンアップ時に、たとえば、それがデフォルトではまだだかどうかを確認する1、2へのAtomicIntegerを設定します

通常のJDBCの練習は、あなたがそれを取得したいとあなたは非常に同じメソッドブロック内Connection(とStatementResultSet)を閉じることです。

コードで

Connection connection = null;

try {
    connection = getConnectionSomehow();
    // Do stuff.
} finally {
    if (connection != null) {
        try {
            connection.close();
        } catch (SQLException e) {
            ignoreOrLogItButDontThrowIt(e);
        }
    }
}

これを踏まえて、あなたの質問は私があなたのデザインで何かが間違っだと思います。取得と最短範囲に高価で、外部リソースのそれらの種類を閉じると、潜在的なリソースリークとクラッシュからアプリケーションを保存します。

あなたの本来の意図は、パフォーマンスを向上させるために接続した場合は、

、あなたはのプールの接続のための外観を取る必要があります。このため、たとえば C3P0 のAPIを使用することができます。それとも、それはwebアプリケーションだ場合、DataSourceの味にアプリケーションサーバーの組み込み接続プーリング機能を使用しています。詳細については、アプリケーションサーバー固有のドキュメントを参照してください。

あなたは伝統的なコネクションプーリングを使用していない理由を

私は本当に理解していません。しかし、私はあなたの理由を持ってい負います。

あなたはどのくらいの自由を持っていますか?いくつかのDIフレームワークは、オブジェクトのライフサイクルとスレッドスコープの変数をサポートしていそうであるように(すべてがうまくプロキシ)。あなたはそれらのいずれかを使用できますか?私は、Guiceのは、ライフサイクルとスレッドスコープを処理するために、サードパーティ製のlibが必要になりながら春は、すべての箱から出して、これを行うと思います。

次にあなたはThreadLocal変数の作成やスレッドの作成のいずれかでなければならないのどのくらいのコントロール?私はあなたがThreadLocalの上に完全なコントロールを持っていますが、スレッドの作成時にどれに限定推測しています!

あなたはクリーンアップを含めるようにrun()メソッドを拡張する新しいRunnableをまたはスレッドを監視するためにアスペクト指向プログラミングを使用してもらえますか?また、それが自身を登録できるようにThreadLocalを拡張する必要があります。

あなたはまた、同じ場所での閉鎖を処理する必要がありますので、一度接続をオープンする必要がありました。ご使用の環境に応じて、スレッドは再利用することができると、あなたは、スレッドがアプリケーションのシャットダウンの前にゴミを収集することを期待することはできません。

私は、このための良い解決策は、古典以外には存在しない一般的なケースで考える:リソースを取得するコードは、それを閉じるための責任にする必要があります。

特定のケースでは、あなたがこの程度にスレッドを呼び出している場合は、カスタムパラメータを受け取るメソッドまたは依存性の注入のいくつかのフォームのいずれかを介して、スレッドの開始時に、あなたの方法に関連して渡すことができます。あなたは、接続を提供するコードを持っているので、その後、あなたはそれを削除し、コードを持っています。

必要がないため、1を取得することはありません接続を必要としないコードが閉じられるよう、アノテーションに基づいて依存性の注入は、ここに働くかもしれないが、あなたのデザインが何かを改造しすぎ沿っているように聞こえますそんなます。

それは、サブクラスのListプロパティを設定するように

ThreaedLocal内のget()メソッドをオーバーライドします。 このプロパティは、簡単にget()メソッドは、特定のスレッドのために呼び出されたかどうかを判断するために照会することができます。あなたは、その場合には、それをクリーンアップするためにThreadLocalにアクセスすることができます。

のコメントに応じて更新

だった私たちがやった。

@Override
public void run() {
  try {
    // ...
  } finally {
    resource.close();
  }
}

基本的にはちょうど常に(そしておそらくオープンと)スレッドを通じてすべてのパスのためにそれを閉じます。ケースでは、そこに誰を支援します。)

私は同じ問題で探しています。それが廃止されたものの、これまであなたは、ファイナライズ()を使用しなければならないように見えます。タスクがいくつかキュータに提出されているように、スレッドは正確に終了し、あなたが知っていることはないだろう、エグゼキュータはあなたを示していない限り、それはあなたには、いくつかのエグゼキュータのコントロールを持っている拡張を意味します。

あなたはThreadPoolExecutorを拡張することにより、エグゼキュータを構築する場合は、

たとえば、あなたがそれを達成するためにafterExecution()と終了()メソッドをオーバーライドすることができます。通常、後者ながら異常出る糸の元

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top