特定の回答へのコメントに触発されて、一意のキーに依存し、それらをロックするマルチトン パターンのスレッド セーフな実装を作成しようとしました (この質問に関するJB Nizetの回答からアイデアを得ました)。
質問
私が提供した実装は実行可能ですか?
マルチトン(またはシングルトン)が一般的に良いパターンであるかどうかには興味がありません。それは議論になります。クリーンで機能する実装が欲しいだけです。
短所:
- コンパイル時に作成するインスタンスの数を知っておく必要があります。
長所
- クラス全体、またはマップ全体のロックはありません。への同時通話
getInstance
が可能です。 - unbounded
int
またはだけでなく、キー オブジェクトを介してインスタンスをString
取得するため、メソッド呼び出し後に null 以外のインスタンスを確実に取得できます。 - スレッドセーフです(少なくともそれが私の印象です)。
public class Multiton
{
private static final Map<Enum<?>, Multiton> instances = new HashMap<Enum<?>, Multiton>();
private Multiton() {System.out.println("Created instance."); }
/* Can be called concurrently, since it only synchronizes on id */
public static <KEY extends Enum<?> & MultitionKey> Multiton getInstance(KEY id)
{
synchronized (id)
{
if (instances.get(id) == null)
instances.put(id, new Multiton());
}
System.out.println("Retrieved instance.");
return instances.get(id);
}
public interface MultitionKey { /* */ }
public static void main(String[] args) throws InterruptedException
{
//getInstance(Keys.KEY_1);
getInstance(OtherKeys.KEY_A);
Runnable r = new Runnable() {
@Override
public void run() { getInstance(Keys.KEY_1); }
};
int size = 100;
List<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < size; i++)
threads.add(new Thread(r));
for (Thread t : threads)
t.start();
for (Thread t : threads)
t.join();
}
enum Keys implements MultitionKey
{
KEY_1;
/* define more keys */
}
enum OtherKeys implements MultitionKey
{
KEY_A;
/* define more keys */
}
}
マップのサイズ変更と、同期する列挙型の誤用を防止しようとしました。私がそれを乗り越える前に、それは概念実証のようなものです! :)
public class Multiton
{
private static final Map<MultitionKey, Multiton> instances = new HashMap<MultitionKey, Multiton>((int) (Key.values().length/0.75f) + 1);
private static final Map<Key, MultitionKey> keyMap;
static
{
Map<Key, MultitionKey> map = new HashMap<Key, MultitionKey>();
map.put(Key.KEY_1, Keys.KEY_1);
map.put(Key.KEY_2, OtherKeys.KEY_A);
keyMap = Collections.unmodifiableMap(map);
}
public enum Key {
KEY_1, KEY_2;
}
private Multiton() {System.out.println("Created instance."); }
/* Can be called concurrently, since it only synchronizes on KEY */
public static <KEY extends Enum<?> & MultitionKey> Multiton getInstance(Key id)
{
@SuppressWarnings ("unchecked")
KEY key = (KEY) keyMap.get(id);
synchronized (keyMap.get(id))
{
if (instances.get(key) == null)
instances.put(key, new Multiton());
}
System.out.println("Retrieved instance.");
return instances.get(key);
}
private interface MultitionKey { /* */ }
private enum Keys implements MultitionKey
{
KEY_1;
/* define more keys */
}
private enum OtherKeys implements MultitionKey
{
KEY_A;
/* define more keys */
}
}