Java : Cleaner - API使用例

Cleaner (Java SE 18 & JDK 18) の使用例まとめです。
だいたいのメソッドを網羅済みです。
API仕様のおともにどうぞ。


概要

Cleanerは、一連のオブジェクト参照と対応するクリーニング・アクションを管理します。

クラス構成

Cleanerクラスを使うと、対象となるオブジェクトがクリアされるときに、登録しておいたアクションを実行できます。
イメージとしては Objectクラスfinalize に近いです。

Cleanerクラスは、内部的には ファントム参照 を利用しています。
ファントム参照がクリアされるタイミングで (つまり対象オブジェクトが finalize されたあと) 、登録したアクションを実行します。

class Foo {
    @SuppressWarnings("removal")
    @Override
    protected void finalize() {
        System.out.println("Finalize!");
    }
}

var foo = new Foo();

final var cleaner = Cleaner.create();

cleaner.register(foo, () -> {
    System.out.println("Clean!");

    final var current = Thread.currentThread();
    System.out.printf("  (thread id = %d, daemon = %b)%n", current.getId(), current.isDaemon());
});

System.out.println("-- start -- (thread id = " + Thread.currentThread().getId() + ")");

foo = null;

System.out.println("-- gc --");
System.gc();

TimeUnit.SECONDS.sleep(3);
System.out.println("-- sleep --");

System.out.println("-- gc --");
System.gc();

TimeUnit.SECONDS.sleep(3);
System.out.println("-- sleep --");

// 結果
// ↓
//-- start -- (thread id = 1)
//-- gc --
//Finalize!
//-- sleep --
//-- gc --
//Clean!
//  (thread id = 19, daemon = true)
//-- sleep --

個人的には、Cleaner クラスを使わずに、AutoCloseabletry-with-resources文 で確実に後処理するのをおすすめします。


メソッド

static Cleaner create ()

新しいCleanerを返します。

class Foo {
    @SuppressWarnings("removal")
    @Override
    protected void finalize() {
        System.out.println("Finalize!");
    }
}

var foo = new Foo();

final var cleaner = Cleaner.create();

cleaner.register(foo, () -> {
    System.out.println("Clean!");

    final var current = Thread.currentThread();
    System.out.printf("  (thread id = %d, daemon = %b)%n", current.getId(), current.isDaemon());
});

System.out.println("-- start -- (thread id = " + Thread.currentThread().getId() + ")");

foo = null;

System.out.println("-- gc --");
System.gc();

TimeUnit.SECONDS.sleep(3);
System.out.println("-- sleep --");

System.out.println("-- gc --");
System.gc();

TimeUnit.SECONDS.sleep(3);
System.out.println("-- sleep --");

// 結果
// ↓
//-- start -- (thread id = 1)
//-- gc --
//Finalize!
//-- sleep --
//-- gc --
//Clean!
//  (thread id = 19, daemon = true)
//-- sleep --

static Cleaner create (ThreadFactory threadFactory)

ThreadFactoryからThreadを使用して新しいCleanerを返します。

class Foo {
    @SuppressWarnings("removal")
    @Override
    protected void finalize() {
        System.out.println("Finalize!");
    }
}

var foo = new Foo();

final var cleaner = Cleaner.create(r -> new Thread(r, "ABC"));

cleaner.register(foo, () -> {
    System.out.println("Clean!");

    final var current = Thread.currentThread();
    System.out.printf("  (thread id = %d, name = %s, daemon = %b)%n",
            current.getId(), current.getName(), current.isDaemon());
});

System.out.println("-- start -- (thread id = " + Thread.currentThread().getId() + ")");

foo = null;

System.out.println("-- gc --");
System.gc();

TimeUnit.SECONDS.sleep(3);
System.out.println("-- sleep --");

System.out.println("-- gc --");
System.gc();

TimeUnit.SECONDS.sleep(3);
System.out.println("-- sleep --");

// 結果
// ↓
//-- start -- (thread id = 1)
//-- gc --
//Finalize!
//-- sleep --
//-- gc --
//Clean!
//  (thread id = 19, name = ABC, daemon = true)
//-- sleep --

Cleaner.Cleanable register (Object obj, Runnable action)

オブジェクトにファントム到達可能になったときに実行するオブジェクトとクリーニング・アクションを登録します。

class Foo {
}

final var foo = new Foo();
final var cleaner = Cleaner.create();

final var cleanable = cleaner.register(foo, () -> {
    System.out.println("Clean!");

    final var current = Thread.currentThread();
    System.out.printf("  (thread id = %d, daemon = %b)%n", current.getId(), current.isDaemon());
});

System.out.println("-- start -- (thread id = " + Thread.currentThread().getId() + ")");

cleanable.clean();

// 結果
// ↓
//-- start -- (thread id = 1)
//Clean!
//  (thread id = 1, daemon = false)

関連記事

ページの先頭へ