/* * 練習問題17.3 p.406 * ハッシュコードを使用する代わりに、キーを管理することで参照オブジェクトを使用するように、 * リソース実装クラスを書き直しなさい。 */ package ch17.ex17_03; import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.Map; public class ResourceManager { final ReferenceQueue<Object> queue; final Map<Reference<?>, Resource> refs; final Thread reaper; boolean shutdown = false; public ResourceManager() { queue = new ReferenceQueue<Object>(); refs = new HashMap<Reference<?>, Resource>(); reaper = new ReaperThread(); reaper.start(); // ... リソースの初期化 ... } public synchronized void shutdown() { if (!shutdown) { shutdown = true; reaper.interrupt(); } } public synchronized Resource getResource(Object key) { if (shutdown) { throw new IllegalStateException(); } Resource res = new ResourceImpl(key); Reference<?> ref = new PhantomReference<Object>(key, queue); refs.put(ref, res); return res; } private static class ResourceImpl implements Resource { // int keyHash; SoftReference<Object> implKey; boolean needsRelease = false; ResourceImpl(Object key) { // keyHash = System.identityHashCode(key); implKey = new SoftReference<Object>(key); // .. 外部リソースの設定 needsRelease = true; } public void use(Object key, Object... args) { // if (System.identityHashCode(key) != keyHash) if (!implKey.get().equals(key)) { throw new IllegalArgumentException("wrong key"); } // ... リソースの使用 ... System.out.println(key.toString() + " is used. "); } public synchronized void release() { if (needsRelease) { needsRelease = false; // ... リソースの解放 ... implKey.clear(); } } } class ReaperThread extends Thread { public void run() { // 割り込まれるまで実行 while(true) { try { Reference<?> ref = queue.remove(); Resource res = null; synchronized(ResourceManager.this) { res = refs.get(ref); refs.remove(ref); } res.release(); ref.clear(); System.out.println("reaper!"); } catch (InterruptedException ex) { break; // すべて終了 } } } } public static void main(String[] args) { ResourceManager test = new ResourceManager(); System.out.println("resource1"); String key1 = "key1"; Resource resource1 = test.getResource(key1); resource1.use(key1); resource1.release(); System.out.println("resource2"); String key2 = "key2"; try { Resource resource2 = test.getResource(key2); resource2.use(key1); resource2.release(); } catch(Exception e) { System.out.println(e); } test.shutdown(); } }