0

In a parallel application, threads(32) in a thread group use a shared unmanaged and standalone disposable object.

We have the same thing in our c/c++ app, and there I use shared_ptr<> in order to let object dispose and finalize just after there is no need to the object.

I just tried to apply the same thing in Java, and I faced with finalize() method. But there are some problems, because of GC is so lazy sometimes, the object doesn't even identified as unreachable object for disposing/finalizing, sometimes it is called, but there is no warranty GC lets the object invoke the finalize() completely.

So I just came with another complex solution which I just count down and track the threads are using the object which it doesn't work too, but I know this is not a reliable solution, and I know I will faced with unexpected results.

I'm just wonder if there is something equivalent to shared_ptr<> in java, or is it possible to handle the object via JNI?

Any ideas?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • 1
    As I found out in [this question](http://stackoverflow.com/questions/23155261/rendering-using-weak-references-and-the-gc), some languages simply do not work this way. You need to rethink your solution to work with the language, not bash the language until it works like C++. – OMGtechy May 17 '14 at 18:50
  • Indeed: `shared_ptr` relies heavily on C++'s object construction/destruction semantics, which are not available in Java. The `try-with-resources` statement is the nearest local equivalent, and requires a different way of thinking about the problem, but can be used to implement a neat and safe solution to this kind of problem. – Jules May 18 '14 at 00:08
  • 3
    I strongly disagree that there is anything "unclear" about this question. It already has a good answer, and certainly should not have been closed. – Jules May 18 '14 at 00:35

6 Answers6

5

Doing what you want well needs some effort, and will never feel natural in Java, because deterministic cleanup of resources is foreign to Java. It has gotten a bit better since Java 7 though.

The best way to work around it is this:

  1. Add a counter of type java.util.concurrent.AtomicInteger to your java wrapper, initialised at 1 (Thanks @Jules for that, now avoiding synchronized!).
  2. Add an addRef method, which throws if the counter is 0, returning this for better use in the try-statement.
  3. Implement java.lang.AutoCloseable: close decreases the count when not 0, and releases the resource when the count reaches 0.
  4. Add a finalizer as a final safety-net: Log failure to properly release the resource earlier, and do the final release.
  5. Add a comment to every variable / argument which owns such a reference and is not a try-with-resource, so you know to call addRef and close as appropriate.

A try-with-resources-block using the java wrapper:

try(resource.AddRef()) {
    // Do your thing
}
Community
  • 1
  • 1
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • 2
    Presumably, `addRef` (standard Java naming convention would have the method name starting with a lower-case letter) should increment the counter. Also, if you want to avoid the overhead of using `synchronized` methods, a `java.util.concurrent.AtomicInteger` could be used instead. – Jules May 18 '14 at 00:05
  • @Jules: Thanks for the suggestion. Integrated it. – Deduplicator May 18 '14 at 00:22
  • Thanks bro, the more I study Java, the more I love the old school friend `C`. –  May 18 '14 at 18:04
2

tldr; There is no general way to force "destruction" of an object in Java - and the finalize method is called only when an object is collected (which might be never!)

The only resources that one generally needs to worry about are external resources such as files or stream - the general approach to handle such a case it use manual lifetime management through close/AutoClosable (with the finalizer, if used, only being a "safety"). Lifetime is left entirely in the caller and "closing" a resource (e.g. a File) too early would make it invalid to use elsewhere.

This manual management can be done with an acquire/release pool (when all the acquires are released, the "use count" goes to zero, and close is called on the underlying resource); a variation is with a semaphore, if the count can be pinned in advance.

On the other hand, internally managed but-no-longer-reachable objects/resources will be evicted as needed by the GC and so there is (generally) no need to worry about their lifetime.

Community
  • 1
  • 1
user2864740
  • 60,010
  • 15
  • 145
  • 220
  • @Deduplicator Thanks for pointing that out. It must be done manually - I've added a small (and albeit vague) bit to my answer for "how" this manually process can be done. – user2864740 May 17 '14 at 19:37
2

You can create a simple manager object which knows how to create and dispose of the resource in question. You implement a synchronized checkout() and checkin() method on the object. the checkout method creates the object on the first call, increments a reference count, and returns a reference to the object. the checkin method decrements the reference count, and when it goes to zero, it disposes of the object. then you just scope all usage of the object with a try/finally pattern (similar to lock/unlock):

Resource res = manager.checkout();
try {
  // ... work with resource here ...
} finally {
  manager.checkin(res);
}

Note, you could probably make this a little cleaner using the java 7 AutoCloseable.

jtahlborn
  • 52,909
  • 5
  • 76
  • 118
1

Depends on how you look at it.

Either there's no such thing as anything like shared_ptr in Java because there's no such thing as value objects in Java (except the raw types like int) and RAII doesn't exist there.

Or...everything in Java is just like shared_ptr because everything is a share reference that acts more like a reference counted pointer.

Edward Strange
  • 40,307
  • 7
  • 73
  • 125
1

The equivalent in Java is just a normal object reference; let GC do its work. You should pretty much never use finalize.

An alternative is to use a PhantomReference - this allows you to set up some processing to happen at some point after the object ceases to be referenced.

What is it about your objects that requires some action when it ceases to be referenced?

Alan Stokes
  • 18,815
  • 3
  • 45
  • 64
  • There is some huge and clean up required just after the object is unreachable and no any thread needs the object, how would I utilize the `PhantomRef` bro? any example? –  May 17 '14 at 18:50
  • What are you cleaning up? Other objects references will also be garbage collected in due course. – Alan Stokes May 17 '14 at 18:51
  • The problem is, many times(90%), GC doesn't find the object unreachable, I think it doesn't even run. sometimes at the end of application cycle, and when it calls, there is no any 100% chance to let finalize does its process. –  May 17 '14 at 18:53
  • @user Yes, but what actual problem does that cause? – Alan Stokes May 17 '14 at 18:56
  • The clean process should trigger some external module, there is no any problem in c app, but in java, GC doesn't collect the object, in fact it doesn't even scan the memory, I check the heap size during the application life cycle, sometimes GC collect the object and I had some situation it halts the finalize method process at the middle of method call. –  May 17 '14 at 21:23
  • @user2889419: Forget `finalize`. There's no problem it solves, just a bunch of problems it creates. Use `try-finally` (or equivalent) for each such resource and drop `finalize`. Unlike in C++, the GC takes care of all memory, i.e., of nearly everything. The price is that you must carefully take care about the non-memory resources yourself. – maaartinus May 18 '14 at 02:12
  • Thanks bro, really appreciate your help, I wish I could not start Java. @maaartinus –  May 18 '14 at 18:10
  • @user2889419 You're welcome. You may start to love Java as it's cool in most aspects (lack of [RAII](http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) is one of the exceptions) and the community is great. I also have a C++ background and I'd never go back. – maaartinus May 18 '14 at 18:27
1

There is no such thing - you don't use pointers or free objects the moment you're done with them in Java. Well, you can do that, but chances are - you'd be doing it wrong.

If you must do something when all threads are finished with handling an object, you should track its use yourself and clean up when you're done.

zmbq
  • 38,013
  • 14
  • 101
  • 171
  • 1
    you'd be "doing it wrong" for normal java objects, but assuming the object in question correlates to an external (scarce) resource (like a socket, database connection or lock), then you'd be "doing it right". – jtahlborn May 17 '14 at 19:13