モジュール jdk.incubator.foreign
パッケージ jdk.incubator.foreign

インタフェースResourceScope

すべてのスーパー・インタフェース:
AutoCloseable

public sealed interface ResourceScope extends AutoCloseable
リソース・スコープは、1つ以上のリソースのライフサイクルを管理します。 リソース・スコープに関連付けられたリソース(e.g. MemorySegment)は、リソース・スコープがalive (isAlive()を参照してください)である間、およびリソース・スコープ(もしあれば)に関連付けられたスレッドによってのみアクセスできます。

明示的なリソース・スコープ

newConfinedScope()newSharedScope()サポート「確定的割当解除」から取得されたリソース・スコープ。これらのリソース・スコープを「明示的なスコープ」と呼びます。 明示的なリソース・スコープは、明示的に(close()を参照してください)を終了できます。 リソース・スコープがクローズされると、aliveではなくなります(isAlive()を参照)。そのスコープ(例: MemorySegmentインスタンスへのアクセスの試行)に関連付けられたリソースに対する後続の操作は、IllegalStateExceptionで失敗します。

リソース・スコープを閉じると、そのスコープ(addCloseAction(Runnable)を参照してください)に関連付けられたすべてのクリーンアップ・アクションが呼び出されます。 さらに、リソース・スコープを閉じると、そのスコープに関連付けられた基礎となるメモリー・リソースの解放がトリガーされる可能性があります。たとえば、次のようになります:

明示的なスコープをCleanerインスタンス(newConfinedScope(Cleaner)およびnewSharedScope(Cleaner)を参照してください)に関連付けることができます。 これらのリソース・スコープは、managedリソース・スコープと呼ばれます。 管理対象リソース・スコープは、スコープ・インスタンスがunreachableになると自動的にクローズされます。

管理対象スコープは、予測可能な確定的リソースの割り当て解除を可能にしつつ、偶発的なネイティブ・メモリー・リークを防ぐために役立ちます。 管理対象リソース・スコープが明示的にクローズされている場合、スコープが到達不能になると、それ以上のアクションは実行されません。つまり、管理対象かどうかに関係なく、リソース・スコープに関連付けられたクリーンアップ・アクション(addCloseAction(Runnable)を参照してください)は「1回のみ」と呼ばれます。

暗黙的なリソース・スコープ

newImplicitScope()から取得したリソース・スコープを明示的にクローズすることはできません。 これらのリソース・スコープを「暗黙的なスコープ」と呼びます。 暗黙的なリソース・スコープでclose()をコールすると、常に例外が発生します。 暗黙的なスコープに関連付けられたリソースは、スコープ・インスタンスがunreachableになると解放されます。

重要な暗黙的なリソース・スコープは「グローバル・スコープ」というものです。グローバル・スコープは、unreachableになることが保証される暗黙的なスコープです。 結果として、グローバル・スコープはそれに関連付けられたリソースの解放を試行しません。 このようなリソースは、必要に応じてクライアントから独立して管理する必要があります。

スレッド制限

リソース・スコープは、さらに2つのカテゴリに分けることができます: thread-confinedリソース・スコープおよびsharedリソース・スコープ。

限定されたリソース・スコープ(newConfinedScope()を参照してください)は、強力なスレッド限定保証をサポートします。 作成時に、「所有者スレッド」(通常は作成操作(ownerThread()を参照してください)を開始したスレッド)が割り当てられます。 限定されたリソース・スコープを作成すると、所有者スレッドのみが、このリソース・スコープに関連付けられたリソースを直接操作できます。 所有者スレッド以外のスレッドからリソース・アクセスを実行しようとすると、実行時エラーが発生します。

一方、共有リソース・スコープ(newSharedScope()およびnewImplicitScope()を参照)には所有者スレッドがありません。この共有リソース・スコープに関連付けられたリソースは、複数のスレッドからアクセスできます。 これは、複数のスレッドが同じリソース (例:パラレル処理の場合)に同時にアクセスする必要がある場合に役立ちます。 たとえば、クライアントが共有セグメントからSpliteratorを取得すると、セグメントをスライスし、複数のスレッドを分離したセグメント・スライスに対して並行して作業できます。 次のコードを使用すると、メモリー・セグメント内のすべてのint値を並列に合計できます:


SequenceLayout SEQUENCE_LAYOUT = MemoryLayout.sequenceLayout(1024, MemoryLayouts.JAVA_INT);
try (ResourceScope scope = ResourceScope.newSharedScope()) {
    MemorySegment segment = MemorySegment.allocateNative(SEQUENCE_LAYOUT, scope);
    VarHandle VH_int = SEQUENCE_LAYOUT.elementLayout().varHandle(int.class);
    int sum = StreamSupport.stream(segment.spliterator(SEQUENCE_LAYOUT), true)
        .mapToInt(s -> (int)VH_int.get(s.address()))
        .sum();
}
 

強力な共有リソース・スコープは慎重に使用する必要があります: 別のスレッドからスコープがクローズされている間に共有スコープに関連付けられたリソースにアクセスする場合、アクセス・スレッドとクローズ・スレッドの両方で例外が発生する可能性があります。 クライアントは、共有リソース・スコープを繰り返し (例:例外がスローされなくなるまでclose()をコールし続ける)を閉じようとしないでください。 かわりに、共有リソース・スコープのクライアントでは、共有リソース・スコープをクローズするスレッドが、同じスコープによって管理されるリソースにアクセスしているスレッドに対して競合しないように、適切な同期メカニズム(例:リソース・スコープ・ハンドルの使用)が必ず配置されるようにする必要があります。

リソース・スコープ・ハンドル

リソース・スコープは、1つ以上のリソース・スコープ「ハンドル」を取得することでnon-closeableにできます(acquire()を参照)。 リソース・スコープ・ハンドルを使用して、特定のリソース・スコープ(明示的または暗黙的)に関連付けられたリソースを一定期間解放できないことを確認できます - 例:スコープに関連付けられた1つ以上のリソースを含むコードの重要なリージョン中。 たとえば、明示的なリソース・スコープは、そのスコープに対して取得されたすべてのハンドルが(close()を参照してください)をクローズした後にのみクローズできます。 これは、クライアントがメモリー・セグメントに対して重要な操作を実行する必要があるときに、セグメントが解放されないようにする必要がある場合に便利です。次のように実行できます:

MemorySegment segment = ...
ResourceScope.Handle segmentHandle = segment.scope().acquire()
try {
   <critical operation on segment>
} finally {
   segment.scope().release(segmentHandle);
}
 
暗黙的なリソース・スコープの取得も可能ですが、多くの場合、不必要ではありません: 暗黙的なスコープに関連付けられたリソースは、スコープがunreachableになった場合にのみ解放されるため、クライアントはReference.reachabilityFence(Object)のように、暗黙的なスコープに関連付けられたリソースが途中でリリースされていないことを確認できます。 つまり、前述のコード・スニペットは、暗黙的なスコープに対して(トリビアル)も機能します。
実装要件:
このインタフェースの実装は不変、スレッド・セーフ、およびvalue-basedです。
  • ネストされたクラスのサマリー

    ネストされたクラス
    修飾子と型
    インタフェース
    説明
    static interface 
    抽象化はリソース・スコープ・ハンドルをモデリングします。
  • メソッドのサマリー

    修飾子と型
    メソッド
    説明
    このリソース・スコープに関連付けられたリソース・スコープ・ハンドルを取得します。
    void
    リソース・スコープがクローズされたときに実行されるカスタム・クリーンアップ・アクションを追加します。
    void
    このリソース・スコープを閉じます。
    常に有効とみなされる暗黙的なスコープを返します。
    boolean
    このリソース・スコープは稼働していますか。
    boolean
    このリソース・スコープは「暗黙的なスコープ」ですか。
    新しい限定スコープを作成します。
    Cleanerによって管理される新しい限定スコープを作成します。
    新しい「暗黙的なスコープ」を作成します。
    新しい共有スコープを作成します。
    Cleanerによって管理される新しい共有スコープを作成します。
    このリソース・スコープを所有するスレッド。
    void
    指定されたリソース・スコープ・ハンドルを解放します。
  • メソッドの詳細

    • isAlive

      boolean isAlive()
      このリソース・スコープは稼働していますか。
      戻り値:
      true。このリソース・スコープが存続している場合。
      関連項目:
    • ownerThread

      Thread ownerThread()
      このリソース・スコープを所有するスレッド。
      戻り値:
      このリソース・スコープを所有するスレッド、またはこのリソース・スコープが共有されている場合はnull
    • isImplicit

      boolean isImplicit()
      このリソース・スコープは「暗黙的なスコープ」ですか。
      戻り値:
      このスコープが「暗黙的なスコープ」の場合はtrue。
      関連項目:
    • close

      void close()
      このリソース・スコープを閉じます。 副作用として、この操作が例外なく完了した場合、このスコープは「生きていない」としてマークされ、このスコープに関連付けられたリソースに対する後続の操作はIllegalStateExceptionで失敗します。 また、クローズが成功すると、このリソース・スコープに関連付けられたすべてのネイティブ・リソースが解放されます。
      定義:
      close、インタフェースAutoCloseable
      APIのノート:
      この操作はべき等ではありません。つまり、すでに閉じているリソース・スコープalwaysをクローズすると、例外がスローされます。 これは意図的な設計の選択を反映しています: リソース・スコープの状態遷移はクライアント・コードでマニフェストである必要があります。これらの遷移のいずれかが失敗すると、基礎となるアプリケーション・ロジックのバグが表示されます。
      例外:
      IllegalStateException - 次の条件のいずれかが満たされた場合:
      • このリソース・スコープはaliveではありません
      • このリソース・スコープは制限されており、このメソッドは、このリソース・スコープを所有するスレッド以外のスレッドから呼び出されます
      • このリソース・スコープは共有され、このメソッドを呼び出したときにこのスコープに関連付けられたリソースにアクセス
      • このリソース・スコープに関連付けられた1つ以上のハンドル(acquire()を参照してください)が「逃す」ではありません
      UnsupportedOperationException - このリソース・スコープがimplicitの場合。
    • addCloseAction

      void addCloseAction(Runnable runnable)
      リソース・スコープがクローズされたときに実行されるカスタム・クリーンアップ・アクションを追加します。 スコープがクローズされると、カスタム・クリーンアップ・アクションが起動される順序は指定されません。
      パラメータ:
      runnable - このスコープに関連付けられるカスタム・クリーンアップ・アクション。
      例外:
      IllegalStateException - このスコープがすでにクローズされている場合。
    • acquire

      このリソース・スコープに関連付けられたリソース・スコープ・ハンドルを取得します。 明示的なリソース・スコープは、それから取得されたすべてのリソース・スコープ・ハンドルがrelease(Handle)リリースされるまでclosedにできません。
      戻り値:
      リソース・スコープ・ハンドル。
    • release

      void release(ResourceScope.Handle handle)
      指定されたリソース・スコープ・ハンドルを解放します。 このメソッドはべき等であり、同じハンドルを複数回リリースしても効果はありません。
      パラメータ:
      handle - リリースするリソース範囲ハンドル。
      例外:
      IllegalArgumentException - 指定されたハンドルがこのスコープに関連付けられていない場合。
    • newConfinedScope

      static ResourceScope newConfinedScope()
      新しい限定スコープを作成します。 結果のスコープはクローズ可能で、Cleanerによって管理されません。
      戻り値:
      新しい限定スコープ。
    • newConfinedScope

      static ResourceScope newConfinedScope(Cleaner cleaner)
      Cleanerによって管理される新しい限定スコープを作成します。
      パラメータ:
      cleaner - 返されたスコープに関連付けられるクリーナ。
      戻り値:
      cleanerによって管理される新しい限定スコープ。
      例外:
      NullPointerException - cleaner == nullの場合。
    • newSharedScope

      static ResourceScope newSharedScope()
      新しい共有スコープを作成します。 結果のスコープはクローズ可能で、Cleanerによって管理されません。
      戻り値:
      新しい共有スコープ。
    • newSharedScope

      static ResourceScope newSharedScope(Cleaner cleaner)
      Cleanerによって管理される新しい共有スコープを作成します。
      パラメータ:
      cleaner - 返されたスコープに関連付けられるクリーナ。
      戻り値:
      cleanerによって管理される新しい共有スコープ。
      例外:
      NullPointerException - cleaner == nullの場合。
    • newImplicitScope

      static ResourceScope newImplicitScope()
      新しい「暗黙的なスコープ」を作成します。 暗黙的なスコープは、暗黙的なクローズのみの機能を持つ管理、共有および非クローズ可能なスコープです。 暗黙的なスコープはガベージ・コレクタによって暗黙的にクローズできるため、不要なメモリー・プレッシャを避けるために、割当て解除パフォーマンスが重要な問題ではない場合にのみ暗黙的なスコープを使用することをお薦めします。
      戻り値:
      新しい暗黙的なスコープ。
    • globalScope

      static ResourceScope globalScope()
      常に有効とみなされる暗黙的なスコープを返します。
      戻り値:
      グローバル・スコープ。