All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.stanford.nlp.util.concurrent.SynchronizedInterner Maven / Gradle / Ivy

package edu.stanford.nlp.util.concurrent;

import java.util.Set;

import edu.stanford.nlp.util.Generics;
import edu.stanford.nlp.util.Interner;

/**
 * 

* For interning (canonicalizing) things in a multi-threaded environment. *

* *

* Maps any object to a unique interned version which .equals the * presented object. If presented with a new object which has no * previous interned version, the presented object becomes the * interned version. You can tell if your object has been chosen as * the new unique representative by checking whether o == intern(o). * The interners use a concurrent map with weak references, meaning that * if the only pointers to an interned item are the interners' backing maps, * that item can still be garbage collected. Since the gc thread can * silently remove things from the backing map, there's no public way to * get the backing map, but feel free to add one at your own risk. *

* Note that in general it is just as good or better to use the * static SynchronizedInterner.globalIntern() method rather than making an * instance of SynchronizedInterner and using the instance-level intern(). *

* * @author Ilya Sherman * @see edu.stanford.nlp.util.Interner */ // TODO would be nice to have this share an interface with Interner public class SynchronizedInterner { protected static final Object globalMutex = new Object(); protected static SynchronizedInterner interner = Generics.newSynchronizedInterner(Interner.getGlobal(), globalMutex); /** * For getting the instance that global methods use. */ public static SynchronizedInterner getGlobal() { synchronized(globalMutex) { return interner; } } /** * For supplying a new instance for the global methods to use. * * @return the previous global interner. */ public static SynchronizedInterner setGlobal(Interner delegate) { synchronized(globalMutex) { SynchronizedInterner oldInterner = SynchronizedInterner.interner; SynchronizedInterner.interner = Generics.newSynchronizedInterner(delegate); return oldInterner; } } /** * Returns a unique object o' that .equals the argument o. If o * itself is returned, this is the first request for an object * .equals to o. */ @SuppressWarnings("unchecked") public static T globalIntern(T o) { synchronized(globalMutex) { return (T) getGlobal().intern(o); } } protected final Interner delegate; protected final Object mutex; public SynchronizedInterner(Interner delegate) { if (delegate == null) throw new NullPointerException(); this.delegate = delegate; this.mutex = this; } public SynchronizedInterner(Interner delegate, Object mutex) { if (delegate == null) throw new NullPointerException(); this.delegate = delegate; this.mutex = mutex; } public void clear() { synchronized(mutex) { delegate.clear(); } } /** * Returns a unique object o' that .equals the argument o. If o * itself is returned, this is the first request for an object * .equals to o. */ public T intern(T o) { synchronized(mutex) { return delegate.intern(o); } } /** * Returns a Set such that each element in the returned set * is a unique object e' that .equals the corresponding element e in the * original set. */ public Set internAll(Set s) { synchronized(mutex) { return delegate.internAll(s); } } public int size() { synchronized(mutex) { return delegate.size(); } } /** * Test method: interns its arguments and says whether they == themselves. * @throws InterruptedException */ public static void main(final String[] args) throws InterruptedException { final Thread[] threads = new Thread[100]; for (int i = 0; i < threads.length; i++) { threads[i] = new Thread(() -> { for (String str : args) { String interned = SynchronizedInterner.globalIntern(str); Thread.yield(); if (interned != str) throw new AssertionError("Interning failed for " + str); } }); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { thread.join(); } } }