Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Guava contributor here.</p> <blockquote> <p>My question is does the library make sure that the object is not being used by any other thread before calling the provided RemovalListener.</p> </blockquote> <p>No, that would be impossible for Guava to do generally -- and a bad idea anyway! If the cache values were <code>Integer</code>s, then because <code>Integer.valueOf</code> reuses <code>Integer</code> objects for integers below 128, you could never expire an entry with a value below 128. That would be <em>bad</em>.</p> <blockquote> <p>Also the documentation of RemovalNotification says that: A notification of the removal of a single entry. The key and/or value may be null if they were already garbage collected. So according to it conn could be null in the above example.</p> </blockquote> <p>To be clear, that's only possible if you're using <code>weakKeys</code>, <code>weakValues</code>, or <code>softValues</code>. (And, as you've correctly deduced, you can't really use any of those if you need to do some teardown on the value.) If you're only using some other form of expiration, you'll never get a null key or value.</p> <p>In general, I don't think a GC-based solution is going to work here. You <em>must</em> have a strong reference to the connection to close it properly. (Overriding <code>finalize()</code> might work here, but that's really a broken thing generally.)</p> <p>Instead, my approach would be to cache references to a wrapper of some sort. Something like</p> <pre><code> class ConnectionWrapper { private Connection connection; private int users = 0; private boolean expiredFromCache = false; public Connection acquire() { users++; return connection; } public void release() { users--; if (users == 0 &amp;&amp; expiredFromCache) { // The cache expired this connection. // We're the only ones still holding on to it. } } synchronized void tearDown() { connection.tearDown(); connection = null; // disable myself } } </code></pre> <p>and then use a <code>Cache&lt;Key, ConnectionWrapper&gt;</code> with a <code>RemovalListener</code> that looks like...</p> <pre><code> new RemovalListener&lt;Key, ConnectionWrapper&gt;() { public void onRemoval(RemovalNotification&lt;Key, ConnectionWrapper&gt; notification) { ConnectionWrapper wrapper = notification.getValue(); if (wrapper.users == 0) { // do the teardown ourselves; nobody's using it wrapper.tearDown(); } else { // it's still in use; mark it as expired from the cache wrapper.expiredFromCache = true; } } } </code></pre> <p>...and then force users to use <code>acquire()</code> and <code>release()</code> appropriately.</p> <p>There's really not going to be any way better than this approach, I think. The only way to detect that there are no other references to the connection is to use GC and weak references, but you can't tear down a connection without a strong reference to it -- which destroys the whole point. You can't guarantee whether it's the <code>RemovalListener</code> or the connection user who'll need to tear down the connection, because what if the user takes more than two minutes to do its thing? I think this is probably the only feasible approach left.</p> <p>(Warning: the above code assumes only one thread will be doing things at a time; it's not synchronized at all, but hopefully if you need it, then this is enough to give you an idea of how it should work.)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload