Data structure to keep things in memory

M

Mike Schilling

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.
 
C

ClassCastException

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.
 
M

Mike Schilling

ClassCastException said:
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.
 
C

ClassCastException

ClassCastException said:
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.)
 
S

Steven Simpson

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).
}
 
L

Lew

ClassCastException said:
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.
 
M

Mike Schilling

ClassCastException said:
ClassCastException said:
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.
 
M

Mike Schilling

Steven Simpson said:
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?
 
S

Steven Simpson

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.
 
M

Mike Schilling

Steven Simpson said:
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.
 
C

ClassCastException

ClassCastException said:
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."
 
M

Mike Schilling

ClassCastException said:
ClassCastException said:
On Sun, 28 Nov 2010 01:56:40 -0800, Mike Schilling wrote:

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
 
C

ClassCastException

That is, the problem handled by

You mean, the problem *not* handled by

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?
 
C

ClassCastException

You mean, the problem *not* handled by


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.
 
S

Steven Simpson

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.

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
SeparateStatisticsObject> as CCE said:
(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?
 
T

Tom Anderson

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
 
M

Mike Schilling

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


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


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.


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
 
M

Mike Schilling

ClassCastException said:
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.
 
C

ClassCastException

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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top