
Data Structure
Networking
RDBMS
Operating System
Java
MS Excel
iOS
HTML
CSS
Android
Python
C Programming
C++
C#
MongoDB
MySQL
Javascript
PHP
- Selected Reading
- UPSC IAS Exams Notes
- Developer's Best Practices
- Questions and Answers
- Effective Resume Writing
- HR Interview Questions
- Computer Glossary
- Who is Who
What is the use of the Cleaner class in Java 9?
In this article, we will learn about the use of the Cleaner class in Java 9. Below, we will first tell the basic usage and then we will know how we can use the Cleaner method practically.
Garbage Collector
An Object that has been created during the program execution is automatically removed by the Garbage Collector (GC). When an object not referenced by any thread and when JVM determines that this object can't be accessed, then it can be eligible for garbage collection.
The finalize() method
The Object class has a finalize() method, which is automatically called by GC before it attempts to remove the object from the heap. The finalize() method has many disadvantages:
- Unreliable
- Slow
Cleaner class
In Java 9, the finalize() method has been deprecated and a new class java.lang.ref.Cleaner added to garbage collection management. An object of Cleaner class gets notified automatically when an object becomes eligible for garbage collection. An object that is being garbage collected needs to be registered with the cleaner object by using the register() method.
The Cleaner variable should be shared across different classes. The Cleaner variable is declared as a static variable and should never be an instance variable.
Basic cleaner usage
Below is an example to use the Cleaner class in Java:
import java.lang.ref.Cleaner; public class CleanerTest { public static void main(String args[]) { System.out.println("TutorialsPoint"); Cleaner cleaner = Cleaner.create(); if(true) { CleanerTest myObject = new CleanerTest(); cleaner.register(myObject, new State()); // register cleaner } for(int i = 1; i <= 10000; i++) { String[] largeObject = new String[1000]; try { Thread.sleep(1); } catch(InterruptedException e) { e.printStackTrace(); } } } private static class State implements Runnable { public void run() { System.out.print("Cleaning action"); } } }
Output
TutorialsPoint Cleaning action
In the above program, we are using the inner class. The inner class instance would hold a reference to the outer class instance regardless of whether they access their instance variable or not. We cannot use the above program practically as it relies totally on the Garbage Collector and doesn't have any control over when the cleanup is triggered.
Effective Use of Cleaner
In the below example, we can see the effective use of a cleaner with AutoCloseable and Try-With-Resources. We will not call the cleaning action explicitly, and the Cleaner stays intact as our safety net.
- Implement the AutoCloseable interface.
- Place the cleaning action call in the close() method.
- ResourceHolder can now be used in a try-with-resources block.
This can be achieved by having the ResourceHolder class:
import java.lang.ref.Cleaner.Cleanable; public class ResourceHolder implements AutoCloseable { private final ExternalResource externalResource; private final Cleaner.Cleanable cleanable; public ResourceHolder(ExternalResource externalResource) { this.externalResource = externalResource; cleanable = AppUtil.getCleaner().register(this, new CleaningAction(externalResource)); } public void doSomethingWithResource() { System.out.printf("Do something extra with the important resource: %s \n", this.externalResource); } @Override public void close() { System.out.println("cleaning action invoked by the close method"); cleanable.clean(); } static class CleaningAction implements Runnable { private ExternalResource externalResource; CleaningAction(ExternalResource externalResource) { this.externalResource = externalResource; } @Override public void run() { // cleaning up the important resources System.out.println("cleaning logic inprogress, releasing up very important resources"); externalResource = null; } } public static void main(String[] args) { // This is an effective way to use cleaners with instances that hold crucial resources try (ResourceHolder resourceHolder = new ResourceHolder(new ExternalResource(1))) { resourceHolder.doSomethingWithResource(); System.out.println("See you"); } /* In case the client code does not use the try-with-resource as expected, the Cleaner will act as the safety-net */ ResourceHolder resourceHolder = new ResourceHolder(new ExternalResource(2)); resourceHolder.doSomethingWithResource(); resourceHolder = null; System.gc(); // to facilitate the running of the cleaning action } }