2.12 Oracle Databaseでのスレッドの概要

Oracle JVMは、単一クライアントの非プリエンプティブ・スレッド・モデルであるデータベース・セッション・モデルに基づきます。Oracle DatabaseのJavaではスレッド・プログラムを実行できますが、実行レベルではシングル・スレッドです。このモデルのJVMは、データベース・セッションに関連するすべてのJavaスレッドを1つのオペレーティング・システム・スレッドで実行します。一度ディスパッチすると、Thread.yield()をコールしてスレッドが明示的に生成され、Socket.read()をコールしてスレッドがブロックされるまで、または実行エンジンによって切り替えられるまで、スレッドは実行を続けます。スレッドが生成され、ブロックされるか、または切り替えられると、JVMは別のスレッドをディスパッチします。

ノート:

11gリリース1(11.1)以降では、Oracle JVMはスレッドの切り替えをサポートします。スレッドの切り替えはJava仕様で義務付けられていませんが、JDK1.5にある新しいjava.util.concurrent APIを適切にサポートするために必要です。

Oracle JVMには、パフォーマンスとスレッド管理を向上させるために、次の機能が追加されました。

  • システム・コールを最小限に抑制します。Oracle JVMでは、標準のシステム・コールのかわりに非システム・ソリューションが採用されました。たとえば、システム・コールを使用せずにモニター同期ブロックやメソッドに入ることが可能です。

  • デッドロックを検出します。

    • Oracle JVMはスレッド間のデッドロックを監視します。デッドロックが発生すると、Oracle JVMはいずれかのスレッドを終了し、oracle.aurora.vm.DeadlockError例外をスローします。

    • シングル・スレッド・アプリケーションは中断できません。スレッドが1つのみのアプリケーションを中断しようとすると、oracle.aurora.vm.LimboError例外がスローされます。

2.12.1 スレッドのライフ・サイクル

シングル・スレッド・アプリケーションでは、次のイベントの発生でコールが終了します。

  • スレッドがコール元に戻された場合。

  • 例外がスローされ、Javaコードで捕捉されなかった場合。

  • System.exit()OracleRuntime.exitSession()またはoracle.aurora.vm.OracleRuntime.exitCall()メソッドがコールされた場合。

  • DBMS_JAVA.endsession()またはDBMS_JAVA.endsession_and_related_state()メソッドがコールされた場合。

初期スレッドが他のJavaスレッドを作成して起動した場合は、次のいずれかの方法でコールが終了します。

  • メイン・スレッドがコール元に戻るか、またはこのスレッドで捕捉されない例外がスローされ、いずれの場合も、他のすべての非デーモン・スレッドは処理されます。非デーモン・スレッドは、その初期メソッドから戻されるか、スレッドで捕捉されない例外がスローされることで終了します。

  • いずれかのスレッドでSystem.exit()OracleRuntime.exitSession()またはoracle.aurora.vm.OracleRuntime.exitCall()メソッドをコールします。

  • DBMS_JAVA.endsession()またはDBMS_JAVA.endsession_and_related_state()メソッドをコールします。

11gリリース1(11.1)以前は、System.exit()またはoracle.aurora.vm.OracleRuntime.exitCall()をコールすることでコールが終了した場合、Oracle JVMは、専用サーバー・モードと共有サーバー・モードの両方でコールをただちに終了し、すべてのスレッドを終了していました。11gリリース1(11.1)以降では、DBMS_JAVAパッケージに次のPL/SQLファンクションを追加することでこの問題に対応しています。

  • FUNCTION endsession RETURN VARCHAR2;

  • FUNCTION endsession_and_related_state RETURN VARCHAR2;

コール時に、Javaプログラムが再帰的に追加のJavaコードを実行することがあります。たとえば、JDBCまたはSQLJを使用してプログラムでSQL問合せを発行すると、Javaで作成されたトリガーがコールされることがあります。コールの存続期間に関するこれまでの説明は、Javaコードへの最上位コールに関するもので、再帰的コールに関する説明ではありません。たとえば、再帰的コール内からSystem.exit()をコールすると、再帰的コールのみではなく、Javaへの最上位コール全体が終了します。

2.12.2 System.exit()、OracleRuntime.exitSession()およびOracleRuntime.exitCall()

System.exit()メソッドでは、Javaの状態が保持されずにJVMが終了します。これによってデータベース・セッションが終了したりクライアントが切断されることはありません。

ただし、その直後にデータベース・セッション自体が終了することが頻発します。また、OracleRuntime.exitSession()でも、Javaの状態が保持されずにJVMが終了します。ただし、これによってデータベース・セッションも終了し、クライアントが切断されます。

OracleRuntime.exitCall()の動作は、OracleRuntime.threadTerminationPolicy()によって異なります。このメソッドでは、boolean値が戻されます。この値がtrueの場合、データベース・コールの終了時に、アクティブなスレッドが休止状態ではなく終了します。

  • 共有サーバー・プロセスでは、threadTerminationPolicy()は常にtrueです。

  • シャドウ(専用)プロセスでは、デフォルト値はfalseです。この値を変更するには、OracleRuntime.setThreadTerminationPolicy()をコールします。

    • 値をfalse(デフォルト値)に設定すると、すべてのスレッドは休止状態になりますが、正常に終了するためのThreadDeath例外が発生します。

    • 値がtrueの場合、すべてのスレッドがただちに終了します。

また、OracleRuntime.callExitPolicy()という別のメソッドがあります。このメソッドでは、OracleRuntime.exitSession()OracleRuntime.exitCall()またはSystem.exit()メソッドがそれまでにコールされていない場合に、コールを終了するタイミングが決定されます。コール終了ポリシーは、OracleRuntime.setCallExitPolicy()を使用して、次のいずれかの値に設定できます。

  • OracleRuntime.EXIT_CALL_WHEN_MAIN_THREAD_TERMINATES

    この値に設定した場合、メイン・スレッドが戻るか、またはメイン・スレッドで捕捉されない例外が発生するとすぐに、デーモンおよび非デーモンの両方を含む残りのすべてのスレッドは次の状態になります。

    • 共有サーバー・モードでは、threadTerminationPolicy()がtrueの場合、常に停止します。

    • threadTerminationPolicy()がfalseの場合、休止状態になります。

  • OracleRuntime.EXIT_CALL_WHEN_ALL_NON_DAEMON_THREADS_TERMINATE

    これはデフォルト値です。この値が設定されると、デーモン・スレッドのみが実行中である場合にコールが終了します。この時点では次のようになります。

    • threadTerminationPolicy()trueの場合、常に共有サーバー・モードにあり、デーモン・スレッドは停止します。

    • threadTerminationPolicy()falseの場合、デーモン・スレッドは次のコールまで休止状態になります。これは、シャドウ(専用)サーバー・モードのデフォルト設定です。

  • OracleRuntime.EXIT_CALL_WHEN_ALL_THREADS_TERMINATE

    この値に設定した場合、すべてのスレッドが戻るか、捕捉されない例外が原因で終了する場合のみ、コールは終了します。この時点では、threadTerminationPolicy()の値に関係なくコールが終了します。