Is there C++ destructor equivalent in Java? [duplicate]
In simplest form, following is the design:
class Session {
Timer t = new Timer();
// ...
};
Whenever, Session
is allocated, I start a timer inside it; the timer will be expired after 10-20 mins. Now, suppose if Session
is destroyed before the timer can expire; then it's a scenario where I must stop timer. I don't know if is there any last method which is always called when Session
is destroyed.
Is there some sort of C++ destructor equivalent in Java, which help me to cancel()
the timer when Session
is destroyed ? (without waiting for GC)
Edit: Please don't retag for C++. I wanted something of that equivalent. The Session
is a phone session which is get destroyed when all the user connected to it are disconnected. Now, there is no Session
method which is called las开发者_运维百科tly nor there is any exception.
No, there's no such thing built into Java. The closest is to write a finalizer, but there's no guarantee that it'll run.
How is a Session destroyed? If there's a method called, by all means put the code there.
How do you create a Session? If you do it within a try/catch block, you can clean up everything in a finally block.
I would write a close() method that took care of it and call it in a finally block.
Unlike C++, you cannot control object deallocation in Java - that is, the GC collects objects whenever it sees fit, merely guaranteeing that it won't collect anything that can be reached through any reference that is in scope at a given time.
There is Object.finalize()
, which acts as a last-chance hook to do cleanup, but the runtime does not guarantee that it gets called at all.
I'd rethink the design and try to come up with a more explicit way of cleaning up your timers.
In Java, variables do not directly represent objects like they do in C++ - variables in Java are references to objects. So an object cannot go out of scope - only a variable that refers to an object can go out of scope.
You can override finalize(), which is a method in class Object that is called by the garbage collector when it is about to permanently discard an object, but that's not exactly the same as a destructor. See the API documentation of the finalize() method in class Object.
First, finalize
is not the equivalent of a destructor. Don't try and use it as one; it won't work. There is nothing built into Java for this, but in some circles, there is a convention to use void dispose()
for this; instead of delete ptr;
, you write ptr.dispose()
. (The memory, of course, gets reclaimed later.) In such cases, it's a good idea to also define finalize
, to generate some sort of internal error if the object is reclaimed before dispose
is called.
Most of the time you can structure the problem so you don't need a destructor.
Creating a Timer for each Session is relatively heavy weight. You are better off submitting a delay task to a ScheduledExecutorService. By making it light weight there would be no need to cancel it. (In fact cancel() doesn't remove it, it is flagged not to run)
You can have a singleton ScheduledExecutorService for simplicty in this case.
class Session {
private static final ScheduledExecutorService timer =
Executors.newSingleThreadScheduledExecutor();
private Future<Void> timeoutFuture = null;
// call every time you want the timeout to start from now.
public void resetTimer() {
if(timeoutFuture != null) timeoutFuture.cancel(false);
timeoutFuture = timer.schedule(new Callable<Void>() {
public Void call() {
sessionTimedOut();
return null;
}
}, TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
void sessionTimedOut() {
// what to do when the session times out.
}
}
Here the expensive component, the ScheduledExecutorService is created once and lives for the life of the application. The Future is discarded when the Session is cleaned up (and the task has expired)
There is not a method like that in java. The finalize()
method, defined in the top-level Object
, may be invoked when the object is being destroyed by the garbage collector, but this is not a behavior you can rely upon.
The best you can do is just set the object to null (removes the reference), which will make it ready for garbage collection.
You may use CDI (Context Dependency Injection) - such as Weld for example or run the program on some JEE server (TomEE, JBoss etc.). Below you have an example of working with databases.
Use appropriate @...Scoped (ApplicationScoped, SessionScoped etc.) annotation on your class, as you prefer eg.:
@ApplicationScoped
public class MyDatabaseFactory implements Serializable {}
Do what you wanted to do in constructor in some method annotated with @PostConstruct:
@PostConstruct
private void initializeObjectsOrConnections() {
// ...
}
Inject your object with @Inject annotation to other places (if you want to):
public class MyApplication {
@Inject
MyDatabaseFactory databaseFactory;
// ...
}
Cleanup, destroy objects and disconnect from database - what you wanted to do in destructor from C++ in method annotated with @PreDestroy of MyDatabaseFactory class, eg.:
@PreDestroy
private void destroyObjectsOrCloseConnections() {
// ...
}
It is very simple to use and we have in Java equivalent of destructor from C++.
精彩评论