Data structure to keep things in memory

Discussion in 'Java' started by Mike Schilling, Nov 28, 2010.

  1. Without going into all the details, I have the following situation:

    There are a set of objects RTS, all of the same type, that gather run-time
    statistics about the running of a program. Various related objects with
    different lifecycles pass them around and use them. I'm interested in when
    each member of RTS is no longer being updated, because I want to collect its
    final statistics , but there's no good way to tell when it's no longer in
    use except via its collection, so when it's created I attach a weak
    reference to it and associate the weak reference with a queue. When the
    reference is delivered, I record the statistics. [1]

    So far so good. The question is, what's the best way to keep the references
    in memory until they can be delivered to the queue? Obviously, I could put
    them into a synchronized HashSet, but I'd prefer to optimize for concurrency
    by minimizing locking. At the moment, I'm using a ConcurrentHashMap, since
    it seems to give the best concurrency for updates. (The usage pattern is a
    bit unusual, since there are effectively no lookups. There's a put() when
    the reference is created, and a remove() when it's pulled out of the
    reference queue.) This is an area where I have very little experience, so
    I'd welcome input from anyone who's worked with these classes.

    1. Obviously, a member of RTS points to a separate statistics object which
    is also pointed to by the weak reference.
     
    Mike Schilling, Nov 28, 2010
    #1
    1. Advertising

  2. On Sun, 28 Nov 2010 00:09:40 -0800, Mike Schilling wrote:

    > Without going into all the details, I have the following situation:
    >
    > There are a set of objects RTS, all of the same type, that gather
    > run-time statistics about the running of a program. Various related
    > objects with different lifecycles pass them around and use them. I'm
    > interested in when each member of RTS is no longer being updated,
    > because I want to collect its final statistics , but there's no good way
    > to tell when it's no longer in use except via its collection, so when
    > it's created I attach a weak reference to it and associate the weak
    > reference with a queue. When the reference is delivered, I record the
    > statistics. [1]
    >
    > So far so good. The question is, what's the best way to keep the
    > references in memory until they can be delivered to the queue?
    > Obviously, I could put them into a synchronized HashSet, but I'd prefer
    > to optimize for concurrency by minimizing locking. At the moment, I'm
    > using a ConcurrentHashMap, since it seems to give the best concurrency
    > for updates. (The usage pattern is a bit unusual, since there are
    > effectively no lookups. There's a put() when the reference is created,
    > and a remove() when it's pulled out of the reference queue.) This is an
    > area where I have very little experience, so I'd welcome input from
    > anyone who's worked with these classes.
    >
    > 1. Obviously, a member of RTS points to a separate statistics object
    > which is also pointed to by the weak reference.


    The RTS object won't be collected, and so won't end up on the reference
    queue, if it's held in a hashmap.

    You need to do something a little bit more complicated: have an RTS
    object with the actual statistics, plus an RTSHandle object for each RTS
    object that holds the RTS object with an ordinary (strong) reference,
    plus a Map<WeakReference<RTSHandle>,RTS> from WeakReferences to the RTS
    objects. When a new RTS is created, the factory method creates an
    RTSHandle as well, and a WeakReference on that handle, and puts a mapping
    from the WeakReference to the RTS into the map as well as returning the
    handle. The rest of your program uses the RTSHandle to access the RTS and
    add statistics, eventually losing all strong references to the RTSHandle.

    When this happens, the RTSHandle becomes weakly reachable as the only
    remaining reference to it is the WeakReference in the map. The
    WeakReference is enqueued. The queue polling thread finds it and uses it
    as a key in the map. Since WeakReference doesn't override Object's
    identity-based equals and hashCode this works even with the referent GCd.
    It accesses the RTS via the map, does its thing, and then removes the map
    entry for that RTS, allowing the RTS and the WeakReference to be GCd.
     
    ClassCastException, Nov 28, 2010
    #2
    1. Advertising

  3. "ClassCastException" <> wrote in message
    news:ict651$av9$-september.org...
    > On Sun, 28 Nov 2010 00:09:40 -0800, Mike Schilling wrote:
    >
    >> Without going into all the details, I have the following situation:
    >>
    >> There are a set of objects RTS, all of the same type, that gather
    >> run-time statistics about the running of a program. Various related
    >> objects with different lifecycles pass them around and use them. I'm
    >> interested in when each member of RTS is no longer being updated,
    >> because I want to collect its final statistics , but there's no good way
    >> to tell when it's no longer in use except via its collection, so when
    >> it's created I attach a weak reference to it and associate the weak
    >> reference with a queue. When the reference is delivered, I record the
    >> statistics. [1]
    >>
    >> So far so good. The question is, what's the best way to keep the
    >> references in memory until they can be delivered to the queue?
    >> Obviously, I could put them into a synchronized HashSet, but I'd prefer
    >> to optimize for concurrency by minimizing locking. At the moment, I'm
    >> using a ConcurrentHashMap, since it seems to give the best concurrency
    >> for updates. (The usage pattern is a bit unusual, since there are
    >> effectively no lookups. There's a put() when the reference is created,
    >> and a remove() when it's pulled out of the reference queue.) This is an
    >> area where I have very little experience, so I'd welcome input from
    >> anyone who's worked with these classes.
    >>
    >> 1. Obviously, a member of RTS points to a separate statistics object
    >> which is also pointed to by the weak reference.

    >
    > The RTS object won't be collected, and so won't end up on the reference
    > queue, if it's held in a hashmap.


    Isn’t it clear that it's the *references* that are in the Map? I had
    thought so. The question is what sort of Map to use to optimize
    concurrency.
     
    Mike Schilling, Nov 28, 2010
    #3
  4. On Sun, 28 Nov 2010 01:56:40 -0800, Mike Schilling wrote:

    > "ClassCastException" <> wrote in message
    > news:ict651$av9$-september.org...
    >> On Sun, 28 Nov 2010 00:09:40 -0800, Mike Schilling wrote:
    >>
    >>> Without going into all the details, I have the following situation:
    >>>
    >>> There are a set of objects RTS, all of the same type, that gather
    >>> run-time statistics about the running of a program. Various related
    >>> objects with different lifecycles pass them around and use them. I'm
    >>> interested in when each member of RTS is no longer being updated,
    >>> because I want to collect its final statistics , but there's no good
    >>> way to tell when it's no longer in use except via its collection, so
    >>> when it's created I attach a weak reference to it and associate the
    >>> weak reference with a queue. When the reference is delivered, I
    >>> record the statistics. [1]
    >>>
    >>> So far so good. The question is, what's the best way to keep the
    >>> references in memory until they can be delivered to the queue?
    >>> Obviously, I could put them into a synchronized HashSet, but I'd
    >>> prefer to optimize for concurrency by minimizing locking. At the
    >>> moment, I'm using a ConcurrentHashMap, since it seems to give the best
    >>> concurrency for updates. (The usage pattern is a bit unusual, since
    >>> there are effectively no lookups. There's a put() when the reference
    >>> is created, and a remove() when it's pulled out of the reference
    >>> queue.) This is an area where I have very little experience, so I'd
    >>> welcome input from anyone who's worked with these classes.
    >>>
    >>> 1. Obviously, a member of RTS points to a separate statistics object
    >>> which is also pointed to by the weak reference.

    >>
    >> The RTS object won't be collected, and so won't end up on the reference
    >> queue, if it's held in a hashmap.

    >
    > Isn’t it clear that it's the *references* that are in the Map?


    Not from his post, it wasn't. He only mentioned RTSs and WeakReferences
    in particular. If he just had RTSs and WeakReference<RTS>s, he had a
    problem either way: if the RTSs are in the map the WeakReferences never
    get enqueued, and if they're not, by the time one's enqueued the
    associated RTS object is gone irretrievably. Using the proposed RTSHandle
    allows to detect when the RTS's *other* references are gone before losing
    the RTS.

    > The question is what sort of Map to use to optimize concurrency.


    ConcurrentHashMap seems like a no-brainer there to me, if there will be
    many calls to the RTS factory from many threads. If not, a normal
    (synchronized) HashMap will suffice. (The RTS factory does all the
    putting in the scheme I outlined; whereas the lookups and removals are
    all done on the single thread that consumes from the ReferenceQueue. The
    critical section in the latter, with a plain synchronized map, would be
    very brief, something like synchronized (map) { x = map.get(wr);
    map.remove(wr); }. So it's the concurrency of access to the factory
    that's the crux here.)
     
    ClassCastException, Nov 28, 2010
    #4
  5. On 28/11/10 09:07, ClassCastException wrote:
    > You need to do something a little bit more complicated: have an RTS
    > object with the actual statistics, plus an RTSHandle object for each RTS
    > object that holds the RTS object with an ordinary (strong) reference,
    > plus a Map<WeakReference<RTSHandle>,RTS> from WeakReferences to the RTS
    > objects. When a new RTS is created, the factory method creates an
    > RTSHandle as well, and a WeakReference on that handle, and puts a mapping
    > from the WeakReference to the RTS into the map as well as returning the
    > handle. The rest of your program uses the RTSHandle to access the RTS and
    > add statistics, eventually losing all strong references to the RTSHandle.
    >
    > When this happens, the RTSHandle becomes weakly reachable as the only
    > remaining reference to it is the WeakReference in the map. The
    > WeakReference is enqueued. The queue polling thread finds it and uses it
    > as a key in the map. Since WeakReference doesn't override Object's
    > identity-based equals and hashCode this works even with the referent GCd.
    > It accesses the RTS via the map, does its thing, and then removes the map
    > entry for that RTS, allowing the RTS and the WeakReference to be GCd.


    I've done something similar, except that I extended WeakReference so
    that it contained a strong reference to the base object (RTS in this
    case), rather than having the Map<Ref,RTS>. The WeakReference class
    also implemented Runnable, so all the polling thread has to do is cast
    the returned reference to Runnable and invoke it. In the OP's case, it
    would look something like this:

    // I'd make RTS an interface...
    public interface RTS { ... }

    // ...then make a (private) class implement it.
    class RTSImpl implements RTS { ... }

    // RTSHandle is just a proxy onto another RTS.
    class RTSHandle implements RTS {
    final RTS base;
    RTSHandle(RTS base) { this.base = base; }
    // all methods just call onto base
    }

    class RTSUser extends WeakReference<RTSHandle> implements Runnable {
    final RTSImpl impl;

    RTSUser(RTSHandle handle,
    ReferenceQueue<? super RTSHandle> queue,
    RTSImpl impl) {
    super(handle, queue);
    this.impl = impl;
    }

    void run() {
    finishWith(impl);
    }
    }

    ReferenceQueue<Object> queue = new ReferenceQueue<Object>();

    // The factory method
    public RTS getRTS() {
    RTSImpl impl = new RTSImpl();
    RTSHandle handle = new RTSHandle(impl);
    RTSUser user = new RTSUser(handle, queue, impl);
    return handle;
    }

    void finishWith(RTSImpl impl) {
    ...
    }

    // Call this in a loop.
    void expireOneRef() throws InterruptedException {
    Runnable action = (Runnable) queue.remove();
    action.run(); // Calls finishWith, if (action instanceof RTSUser).
    }
     
    Steven Simpson, Nov 28, 2010
    #5
  6. Mike Schilling

    Lew Guest

    ClassCastException wrote:
    > ConcurrentHashMap seems like a no-brainer there to me, if there will be
    > many calls to the RTS factory from many threads. If not, a normal
    > (synchronized) HashMap will suffice. (The RTS factory does all the
    > putting in the scheme I outlined; whereas the lookups and removals are
    > all done on the single thread that consumes from the ReferenceQueue. The
    > critical section in the latter, with a plain synchronized map, would be
    > very brief, something like synchronized (map) { x = map.get(wr);
    > map.remove(wr); }.


    Since 'remove(wr)' returns the mapped value, you don't need the 'get()' call.

    > So it's the concurrency of access to the factory that's the crux here.)


    --
    Lew
     
    Lew, Nov 28, 2010
    #6
  7. "ClassCastException" <> wrote in message
    news:icta6n$av9$-september.org...
    > On Sun, 28 Nov 2010 01:56:40 -0800, Mike Schilling wrote:
    >
    >> "ClassCastException" <> wrote in message
    >> news:ict651$av9$-september.org...
    >>> On Sun, 28 Nov 2010 00:09:40 -0800, Mike Schilling wrote:
    >>>
    >>>> Without going into all the details, I have the following situation:
    >>>>
    >>>> There are a set of objects RTS, all of the same type, that gather
    >>>> run-time statistics about the running of a program. Various related
    >>>> objects with different lifecycles pass them around and use them. I'm
    >>>> interested in when each member of RTS is no longer being updated,
    >>>> because I want to collect its final statistics , but there's no good
    >>>> way to tell when it's no longer in use except via its collection, so
    >>>> when it's created I attach a weak reference to it and associate the
    >>>> weak reference with a queue. When the reference is delivered, I
    >>>> record the statistics. [1]
    >>>>
    >>>> So far so good. The question is, what's the best way to keep the
    >>>> references in memory until they can be delivered to the queue?
    >>>> Obviously, I could put them into a synchronized HashSet, but I'd
    >>>> prefer to optimize for concurrency by minimizing locking. At the
    >>>> moment, I'm using a ConcurrentHashMap, since it seems to give the best
    >>>> concurrency for updates. (The usage pattern is a bit unusual, since
    >>>> there are effectively no lookups. There's a put() when the reference
    >>>> is created, and a remove() when it's pulled out of the reference
    >>>> queue.) This is an area where I have very little experience, so I'd
    >>>> welcome input from anyone who's worked with these classes.
    >>>>
    >>>> 1. Obviously, a member of RTS points to a separate statistics object
    >>>> which is also pointed to by the weak reference.
    >>>
    >>> The RTS object won't be collected, and so won't end up on the reference
    >>> queue, if it's held in a hashmap.

    >>
    >> Isn’t it clear that it's the *references* that are in the Map?

    >
    > Not from his post, it wasn't.


    >>>> The question is, what's the best way to keep the
    >>>> ***references*** in memory until they can be delivered to the queue?
    >>>> Obviously, I could put them into a synchronized HashSet
     
    Mike Schilling, Nov 28, 2010
    #7
  8. "Steven Simpson" <> wrote in message
    news:2s.com...
    >
    > I've done something similar, except that I extended WeakReference so
    > that it contained a strong reference to the base object (RTS in this
    > case), rather than having the Map<Ref,RTS>. The WeakReference class
    > also implemented Runnable, so all the polling thread has to do is cast
    > the returned reference to Runnable and invoke it. In the OP's case, it
    > would look something like this:
    >
    > // I'd make RTS an interface...
    > public interface RTS { ... }
    >
    > // ...then make a (private) class implement it.
    > class RTSImpl implements RTS { ... }
    >
    > // RTSHandle is just a proxy onto another RTS.
    > class RTSHandle implements RTS {
    > final RTS base;
    > RTSHandle(RTS base) { this.base = base; }
    > // all methods just call onto base
    > }
    >
    > class RTSUser extends WeakReference<RTSHandle> implements Runnable {
    > final RTSImpl impl;
    >
    > RTSUser(RTSHandle handle,
    > ReferenceQueue<? super RTSHandle> queue,
    > RTSImpl impl) {
    > super(handle, queue);
    > this.impl = impl;
    > }
    >
    > void run() {
    > finishWith(impl);
    > }
    > }
    >
    > ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
    >
    > // The factory method
    > public RTS getRTS() {
    > RTSImpl impl = new RTSImpl();
    > RTSHandle handle = new RTSHandle(impl);
    > RTSUser user = new RTSUser(handle, queue, impl);
    > return handle;
    > }
    >
    > void finishWith(RTSImpl impl) {
    > ...
    > }
    >
    > // Call this in a loop.
    > void expireOneRef() throws InterruptedException {
    > Runnable action = (Runnable) queue.remove();
    > action.run(); // Calls finishWith, if (action instanceof RTSUser).
    > }
    >


    How do you keep the RTSUser's from being GC'd before they are delivered to
    the queue?
     
    Mike Schilling, Nov 28, 2010
    #8
  9. On 28/11/10 18:18, Mike Schilling wrote:
    > "Steven Simpson" <> wrote in message
    > news:2s.com...
    >> class RTSUser extends WeakReference<RTSHandle> implements Runnable {
    >> final RTSImpl impl;
    >>
    >> RTSUser(RTSHandle handle,
    >> ReferenceQueue<? super RTSHandle> queue,
    >> RTSImpl impl) {
    >> super(handle, queue);
    >> this.impl = impl;
    >> }
    >> RTSUser user = new RTSUser(handle, queue, impl);

    >
    > How do you keep the RTSUser's from being GC'd before they are
    > delivered to the queue?


    Hmm, I was under the impression that the ReferenceQueue kept track of
    References, but I see it's the other way around (looking at the source).

    So you need a container of RTSUsers. That was served by the
    Map<Reference<RTSHandle>, RTSImpl> in ClassCastException's original
    suggestion, and a Collection<RTSUser> will suffice here.

    If you have to keep all your RTSImpls anyway, you could make each one
    point to its RTSUser, so the container of RTSImpls indirectly hangs on
    to the RTSUsers. I was originally thinking of a case where getRTS()
    took some sort of key, and mapped it to an RTSImpl, which referenced its
    (multiple) RTSUsers, so that map did the job implicitly.

    Maybe you can get away with a ConcurrentMap<Key, RTSUser>, if you want
    to avoid synchronization:

    ConcurrentMap<Key, RTSUser> map;

    RTS getRTS(Key key) {
    // Create an implementation for 'key', even if we don't
    // ultimately use it.
    RTSImpl impl = createFor(key);

    // Create a proxy for it.
    RTSHandle proxy = proxify(impl);

    // Create a weak reference to the proxy, so we can monitor its
    // discard.
    RTSUser user = new RTSUser(proxy, queue, impl, key);

    for ( ; ; ) {
    // Stick it in the map if there isn't one there already.
    RTSUser oldUser = map.putIfAbsent(key, user);

    // See if we can still get a strong reference to the proxy
    // that the map does hold.
    RTSHandle oldProxy = oldUser.get();

    if (oldProxy == null) {
    // No, we'll have to put ours in anyway, if the old
    // one is still in there.
    if (map.replace(key, oldUser, user))
    // It was still there.
    return proxy;
    // It had gone (perhaps replaced, perhaps removed), so
    // try again.
    continue;
    } else {
    // Yes, we'll just use what's in the map, and discard
    // our impl.
    return oldProxy;
    }
    }
    }

    The RTSUser additionally should take the Key as well, and use
    map.remove(key, this) to remove itself.
     
    Steven Simpson, Nov 28, 2010
    #9
  10. "Steven Simpson" <> wrote in message
    news:2s.com...
    > On 28/11/10 18:18, Mike Schilling wrote:
    >> "Steven Simpson" <> wrote in message
    >> news:2s.com...
    >>> class RTSUser extends WeakReference<RTSHandle> implements Runnable {
    >>> final RTSImpl impl;
    >>>
    >>> RTSUser(RTSHandle handle,
    >>> ReferenceQueue<? super RTSHandle> queue,
    >>> RTSImpl impl) {
    >>> super(handle, queue);
    >>> this.impl = impl;
    >>> }
    >>> RTSUser user = new RTSUser(handle, queue, impl);

    >>
    >> How do you keep the RTSUser's from being GC'd before they are
    >> delivered to the queue?

    >
    > Hmm, I was under the impression that the ReferenceQueue kept track of
    > References, but I see it's the other way around (looking at the source).
    >
    > So you need a container of RTSUsers. That was served by the
    > Map<Reference<RTSHandle>, RTSImpl> in ClassCastException's original
    > suggestion, and a Collection<RTSUser> will suffice here.
    >
    > If you have to keep all your RTSImpls anyway, you could make each one
    > point to its RTSUser, so the container of RTSImpls indirectly hangs on
    > to the RTSUsers. I was originally thinking of a case where getRTS()
    > took some sort of key, and mapped it to an RTSImpl, which referenced its
    > (multiple) RTSUsers, so that map did the job implicitly.
    >
    > Maybe you can get away with a ConcurrentMap<Key, RTSUser>, if you want
    > to avoid synchronization:


    ConcurrentMap is what I'm using. The consensus seems to be that it's the
    best choice.
     
    Mike Schilling, Nov 28, 2010
    #10
  11. On Sun, 28 Nov 2010 10:12:51 -0800, Mike Schilling wrote:

    > "ClassCastException" <> wrote in message
    > news:icta6n$av9$-september.org...
    >> On Sun, 28 Nov 2010 01:56:40 -0800, Mike Schilling wrote:
    >>
    >>> "ClassCastException" <> wrote in message
    >>> news:ict651$av9$-september.org...
    >>>> On Sun, 28 Nov 2010 00:09:40 -0800, Mike Schilling wrote:
    >>>>
    >>>>> Without going into all the details, I have the following situation:
    >>>>>
    >>>>> There are a set of objects RTS, all of the same type, that gather
    >>>>> run-time statistics about the running of a program. Various related
    >>>>> objects with different lifecycles pass them around and use them.
    >>>>> I'm interested in when each member of RTS is no longer being
    >>>>> updated, because I want to collect its final statistics , but
    >>>>> there's no good way to tell when it's no longer in use except via
    >>>>> its collection, so when it's created I attach a weak reference to it
    >>>>> and associate the weak reference with a queue. When the reference
    >>>>> is delivered, I record the statistics. [1]
    >>>>>
    >>>>> So far so good. The question is, what's the best way to keep the
    >>>>> references in memory until they can be delivered to the queue?
    >>>>> Obviously, I could put them into a synchronized HashSet, but I'd
    >>>>> prefer to optimize for concurrency by minimizing locking. At the
    >>>>> moment, I'm using a ConcurrentHashMap, since it seems to give the
    >>>>> best concurrency for updates. (The usage pattern is a bit unusual,
    >>>>> since there are effectively no lookups. There's a put() when the
    >>>>> reference is created, and a remove() when it's pulled out of the
    >>>>> reference queue.) This is an area where I have very little
    >>>>> experience, so I'd welcome input from anyone who's worked with these
    >>>>> classes.
    >>>>>
    >>>>> 1. Obviously, a member of RTS points to a separate statistics object
    >>>>> which is also pointed to by the weak reference.
    >>>>
    >>>> The RTS object won't be collected, and so won't end up on the
    >>>> reference queue, if it's held in a hashmap.
    >>>
    >>> Isn’t it clear that it's the *references* that are in the Map?

    >>
    >> Not from his post, it wasn't.

    >
    >>>>> The question is, what's the best way to keep the ***references*** in
    >>>>> memory until they can be delivered to the queue? Obviously, I could
    >>>>> put them into a synchronized HashSet


    I see a lot of quoted text but no original text. In particular, I *don't*
    see any addressing of the following point:

    "He only mentioned RTSs and WeakReferences in particular. If he just had
    RTSs and WeakReference<RTS>s, he had a problem either way: if the RTSs
    are in the map the WeakReferences never get enqueued, and if they're not,
    by the time one's enqueued the associated RTS object is gone
    irretrievably. Using the proposed RTSHandle allows to detect when the
    RTS's *other* references are gone before losing the RTS."
     
    ClassCastException, Nov 29, 2010
    #11
  12. "ClassCastException" <> wrote in message
    news:icv9de$3u0$-september.org...
    > On Sun, 28 Nov 2010 10:12:51 -0800, Mike Schilling wrote:
    >
    >> "ClassCastException" <> wrote in message
    >> news:icta6n$av9$-september.org...
    >>> On Sun, 28 Nov 2010 01:56:40 -0800, Mike Schilling wrote:
    >>>
    >>>> "ClassCastException" <> wrote in message
    >>>> news:ict651$av9$-september.org...
    >>>>> On Sun, 28 Nov 2010 00:09:40 -0800, Mike Schilling wrote:
    >>>>>
    >>>>>> Without going into all the details, I have the following situation:
    >>>>>>
    >>>>>> There are a set of objects RTS, all of the same type, that gather
    >>>>>> run-time statistics about the running of a program. Various related
    >>>>>> objects with different lifecycles pass them around and use them.
    >>>>>> I'm interested in when each member of RTS is no longer being
    >>>>>> updated, because I want to collect its final statistics , but
    >>>>>> there's no good way to tell when it's no longer in use except via
    >>>>>> its collection, so when it's created I attach a weak reference to it
    >>>>>> and associate the weak reference with a queue. When the reference
    >>>>>> is delivered, I record the statistics. [1]
    >>>>>>
    >>>>>> So far so good. The question is, what's the best way to keep the
    >>>>>> references in memory until they can be delivered to the queue?
    >>>>>> Obviously, I could put them into a synchronized HashSet, but I'd
    >>>>>> prefer to optimize for concurrency by minimizing locking. At the
    >>>>>> moment, I'm using a ConcurrentHashMap, since it seems to give the
    >>>>>> best concurrency for updates. (The usage pattern is a bit unusual,
    >>>>>> since there are effectively no lookups. There's a put() when the
    >>>>>> reference is created, and a remove() when it's pulled out of the
    >>>>>> reference queue.) This is an area where I have very little
    >>>>>> experience, so I'd welcome input from anyone who's worked with these
    >>>>>> classes.
    >>>>>>
    >>>>>> 1. Obviously, a member of RTS points to a separate statistics object
    >>>>>> which is also pointed to by the weak reference.
    >>>>>
    >>>>> The RTS object won't be collected, and so won't end up on the
    >>>>> reference queue, if it's held in a hashmap.
    >>>>
    >>>> Isn’t it clear that it's the *references* that are in the Map?
    >>>
    >>> Not from his post, it wasn't.

    >>
    >>>>>> The question is, what's the best way to keep the ***references*** in
    >>>>>> memory until they can be delivered to the queue? Obviously, I could
    >>>>>> put them into a synchronized HashSet

    >
    > I see a lot of quoted text but no original text.


    There was no need for new text, because it was all explained in the original
    post.

    > In particular, I *don't*
    > see any addressing of the following point:
    >
    > "He only mentioned RTSs and WeakReferences in particular. If he just had
    > RTSs and WeakReference<RTS>s, he had a problem either way: if the RTSs
    > are in the map the WeakReferences never get enqueued, and if they're not,
    > by the time one's enqueued the associated RTS object is gone
    > irretrievably.


    That is, the problem handled by

    >>>1. Obviously, a member of RTS points to a separate statistics object
    >>> which is also pointed to by the weak reference.
     
    Mike Schilling, Nov 29, 2010
    #12
  13. On Sun, 28 Nov 2010 21:29:13 -0800, Mike Schilling wrote:

    > "ClassCastException" <> wrote in message
    > news:icv9de$3u0$-september.org...
    >> In particular, I *don't*
    >> see any addressing of the following point:
    >>
    >> "He only mentioned RTSs and WeakReferences in particular. If he just
    >> had RTSs and WeakReference<RTS>s, he had a problem either way: if the
    >> RTSs are in the map the WeakReferences never get enqueued, and if
    >> they're not, by the time one's enqueued the associated RTS object is
    >> gone irretrievably.

    >
    > That is, the problem handled by
    >
    >>>>1. Obviously, a member of RTS points to a separate statistics object
    >>>> which is also pointed to by the weak reference.


    You mean, the problem *not* handled by

    >>>>1. Obviously, a member of RTS points to a separate statistics object
    >>>> which is also pointed to by the weak reference.


    If the WR points to the actual statistics object you want to keep, it can
    never be dequeued and then the statistics object dumped to a log (or
    whatever you want done with it), because the WR won't be enqueued before
    that object ceases to exist.

    You appeared, in other words, to propose

    WR
    \
    \
    _\|
    _ stats
    /|
    /
    /
    handle

    while you actually need


    WR ---> handle ---> stats

    so the handle can become collectable (and thus the WR get enqueued) while
    the stats object is still live. Everything in your system holds the stats
    object only via the handle object except the CHM, which maps from WR
    directly to stats object and keeps the stats object alive without
    stopping the handle from being collectable when the stats object is no
    longer in use anywhere else. Your queue consumer thread periodically
    wakes up, polls the reference queue, and if it finds a reference uses
    remove() to yank the stats object out of the map, uses the stats object
    for its final task (whatever that is -- logging it somewhere?), and then
    lets its reference to it lapse so the GC can claim the stats object
    itself. (And the WR.)

    Clear now?
     
    ClassCastException, Nov 29, 2010
    #13
  14. On Mon, 29 Nov 2010 09:42:48 +0000, ClassCastException wrote:

    > On Sun, 28 Nov 2010 21:29:13 -0800, Mike Schilling wrote:
    >
    >> "ClassCastException" <> wrote in message
    >> news:icv9de$3u0$-september.org...
    >>> In particular, I *don't*
    >>> see any addressing of the following point:
    >>>
    >>> "He only mentioned RTSs and WeakReferences in particular. If he just
    >>> had RTSs and WeakReference<RTS>s, he had a problem either way: if the
    >>> RTSs are in the map the WeakReferences never get enqueued, and if
    >>> they're not, by the time one's enqueued the associated RTS object is
    >>> gone irretrievably.

    >>
    >> That is, the problem handled by
    >>
    >>>>>1. Obviously, a member of RTS points to a separate statistics object
    >>>>> which is also pointed to by the weak reference.

    >
    > You mean, the problem *not* handled by
    >
    >>>>>1. Obviously, a member of RTS points to a separate statistics object
    >>>>> which is also pointed to by the weak reference.

    >
    > If the WR points to the actual statistics object you want to keep, it
    > can never be dequeued and then the statistics object dumped to a log (or
    > whatever you want done with it), because the WR won't be enqueued before
    > that object ceases to exist.
    >
    > You appeared, in other words, to propose
    >
    > WR
    > \
    > \
    > _\|
    > _ stats
    > /|
    > /
    > /
    > handle
    >
    > while you actually need
    >
    >
    > WR ---> handle ---> stats
    >
    > so the handle can become collectable (and thus the WR get enqueued)
    > while the stats object is still live. Everything in your system holds
    > the stats object only via the handle object except the CHM, which maps
    > from WR directly to stats object and keeps the stats object alive
    > without stopping the handle from being collectable when the stats object
    > is no longer in use anywhere else. Your queue consumer thread
    > periodically wakes up, polls the reference queue, and if it finds a
    > reference uses remove() to yank the stats object out of the map, uses
    > the stats object for its final task (whatever that is -- logging it
    > somewhere?), and then lets its reference to it lapse so the GC can claim
    > the stats object itself. (And the WR.)
    >
    > Clear now?


    Oh, I should probably add -- there's no guarantee a particular object
    will ever get GC'd before VM shutdown. If you want every stats object to
    eventually be processed, you'll also want an orderly shutdown process
    that stops everything else (including, as its penultimate step, the queue
    consumer thread) and then goes over the CHM's .values() Collection
    calling the stats-processing-thingie on each one still in there before
    actually returning/System.exit()ing.
     
    ClassCastException, Nov 29, 2010
    #14
  15. On 28/11/10 20:43, Mike Schilling wrote:
    > "Steven Simpson" <> wrote in message
    > news:2s.com...
    >> Maybe you can get away with a ConcurrentMap<Key, RTSUser>, if you want
    >> to avoid synchronization:

    >
    > ConcurrentMap is what I'm using. The consensus seems to be that it's
    > the best choice.


    I understand your OP better now. Basically, it seems you already had
    the structures we were talking about:

    > 1. Obviously, a member of RTS points to a separate statistics object
    > which is also pointed to by the weak reference.


    Your RTS is the RTSHandle. Your 'separate statistics object' is RTSImpl.

    >> So you need a container of RTSUsers. That was served by the
    >> Map<Reference<RTSHandle>, RTSImpl> in ClassCastException's original
    >> suggestion, and a Collection<RTSUser> will suffice here.


    Your weak reference is my RTSUser. You're using a ConcurrentMap (of
    <Reference<RTS>, Boolean>, I presume) as a kind of set, which
    corresponds to the Collection<RTSUser> above, used to hang on to references.

    Actually, you must have extended WeakReference in order to point it
    (strongly) at the separate statistics object...? Or you're already
    using a ConcurrentMap<Reference<RTS>, SeparateStatisticsObject> as CCE
    suggested.

    > (The usage pattern is a bit unusual, since there are effectively no
    > lookups. There's a put() when the reference is created, and a
    > remove() when it's pulled out of the reference queue.)


    To make it a little less unusual, can you afford to use
    Collections.newSetFromMap here, since you're only using normal puts and
    removes?
     
    Steven Simpson, Nov 29, 2010
    #15
  16. Mike Schilling

    Tom Anderson Guest

    On Sun, 28 Nov 2010, Mike Schilling wrote:

    > Without going into all the details, I have the following situation:
    >
    > There are a set of objects RTS, all of the same type, that gather run-time
    > statistics about the running of a program. Various related objects with
    > different lifecycles pass them around and use them. I'm interested in when
    > each member of RTS is no longer being updated, because I want to collect its
    > final statistics , but there's no good way to tell when it's no longer in use
    > except via its collection, so when it's created I attach a weak reference to
    > it and associate the weak reference with a queue. When the reference is
    > delivered, I record the statistics. [1]
    >
    > So far so good. The question is, what's the best way to keep the references
    > in memory until they can be delivered to the queue?


    Extend the references to make them nodes in a doubly-linked list - give
    them forward and back pointers to others of their kind. Put a pointer to a
    reference somewhere in the rootset, perhaps right next to the reference
    queue. When you create a reference, add it to the list. When you pull a
    dead reference off the queue, remove it from the list - because the
    reference itself is the link, this can be done directly, without needing
    to do a lookup.

    You can make the removal code slightly neater with the old trick of
    hanging the list off a fake head/tail link which never gets removed, to
    avoid having to special-case removing the true head or tail. I'm sure you
    know that, but i mention it for completeness.

    Both addition and removal need to be protected by locks. Adding something
    to the list involves reading one pointer and storing three, with
    essentially no computation, so although there may be contention for the
    lock, it's unlikely to be a bottleneck. If it is, do what the concurrent
    collections do, and stripe the work over multiple parallel lists. Removing
    from the list shouldn't involve any contention, as removals will be well
    spread out, and you may not even be removing in multiple threads.

    I had a bit of a think about whether you could do this lock-free with
    atomics, but i don't think it's a winning strategy; multiple threads
    adding nodes to the same head will always compete, and if that doesn't
    manifest as contention for a lock, it will manifest as retries in a
    lock-free algorithm. Unless you can find a wait-free algorithm to do this;
    i'll buy you a pint if you can.

    tom

    --
    eggflip, brandy, bits of Tia Maria, Beecham's powder, aspirin,
    Benedictine, Alka-Seltzer, black currant juice, a touch of mustard and
    "other things"
     
    Tom Anderson, Nov 29, 2010
    #16
  17. "Steven Simpson" <> wrote in message
    news:2s.com...
    > On 28/11/10 20:43, Mike Schilling wrote:
    >> "Steven Simpson" <> wrote in message
    >> news:2s.com...
    >>> Maybe you can get away with a ConcurrentMap<Key, RTSUser>, if you want
    >>> to avoid synchronization:

    >>
    >> ConcurrentMap is what I'm using. The consensus seems to be that it's
    >> the best choice.

    >
    > I understand your OP better now. Basically, it seems you already had
    > the structures we were talking about:
    >
    >> 1. Obviously, a member of RTS points to a separate statistics object
    >> which is also pointed to by the weak reference.

    >
    > Your RTS is the RTSHandle. Your 'separate statistics object' is RTSImpl.
    >
    >>> So you need a container of RTSUsers. That was served by the
    >>> Map<Reference<RTSHandle>, RTSImpl> in ClassCastException's original
    >>> suggestion, and a Collection<RTSUser> will suffice here.

    >
    > Your weak reference is my RTSUser. You're using a ConcurrentMap (of
    > <Reference<RTS>, Boolean>, I presume) as a kind of set, which
    > corresponds to the Collection<RTSUser> above, used to hang on to
    > references.
    >
    > Actually, you must have extended WeakReference in order to point it
    > (strongly) at the separate statistics object...?


    Yes.

    > Or you're already using a ConcurrentMap<Reference<RTS>,
    > SeparateStatisticsObject> as CCE
    > suggested.
    >
    >> (The usage pattern is a bit unusual, since there are effectively no
    >> lookups. There's a put() when the reference is created, and a
    >> remove() when it's pulled out of the reference queue.)

    >
    > To make it a little less unusual, can you afford to use
    > Collections.newSetFromMap here, since you're only using normal puts and
    > removes?


    That was introduced in 1.6, and I need it to compile with 1.5
    >
     
    Mike Schilling, Nov 29, 2010
    #17
  18. "ClassCastException" <> wrote in message
    news:icvsio$amg$-september.org...
    > You appeared, in other words, to propose
    >
    > WR
    > \
    > \
    > _\|
    > _ stats
    > /|
    > /
    > /
    > handle
    >
    > while you actually need
    >
    >
    > WR ---> handle ---> stats


    It's not a question of proposing: It's all working. It looks like:

    WR --> RTS --> statistics
    --> statistics

    When the RTS is collected, the WR is delivered and the statistics processed.
     
    Mike Schilling, Nov 29, 2010
    #18
  19. On Mon, 29 Nov 2010 08:32:32 -0800, Mike Schilling wrote:

    > "ClassCastException" <> wrote in message
    > news:icvsio$amg$-september.org...
    >> You appeared, in other words, to propose
    >>
    >> WR
    >> \
    >> \
    >> _\|
    >> _ stats
    >> /|
    >> /
    >> /
    >> handle
    >>
    >> while you actually need
    >>
    >>
    >> WR ---> handle ---> stats

    >
    > It's not a question of proposing: It's all working. It looks like:
    >
    > WR --> RTS --> statistics
    > --> statistics
    >
    > When the RTS is collected, the WR is delivered and the statistics
    > processed.


    That should work, then. Your original post didn't make the structure
    clear, and indeed hinted at a different structure, one that wouldn't have
    worked.
     
    ClassCastException, Nov 30, 2010
    #19
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?V2lsbGlhbSBTdWxsaXZhbg==?=

    vs2005 publish website doing bad things, bad things

    =?Utf-8?B?V2lsbGlhbSBTdWxsaXZhbg==?=, Oct 25, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    626
    =?Utf-8?B?UGV0ZXIgQnJvbWJlcmcgW0MjIE1WUF0=?=
    Oct 25, 2006
  2. Replies:
    2
    Views:
    644
  3. A
    Replies:
    27
    Views:
    1,681
    Jorgen Grahn
    Apr 17, 2011
  4. hisan
    Replies:
    1
    Views:
    1,415
    Dan Stromberg
    Jun 25, 2012
  5. mcnewsxp

    keep things in place

    mcnewsxp, Jul 28, 2012, in forum: HTML
    Replies:
    16
    Views:
    761
    Beauregard T. Shagnasty
    Jul 29, 2012
Loading...

Share This Page