Tôi có một giao diện chung cho một số triển khai singleton. Giao diện định nghĩa phương thức khởi tạo có thể ném ngoại lệ đã kiểm tra.Nhà máy đối tượng singleton: mã này có an toàn không?
Tôi cần một nhà máy sẽ trả về các bản triển khai singleton được lưu trong bộ nhớ cache theo yêu cầu và tự hỏi liệu phương pháp tiếp cận sau có an toàn chỉ luồng không?
UPDATE1: Xin đừng đề nghị bất kỳ thư viện phần thứ 3, vì điều này sẽ đòi hỏi để có được giải phóng mặt bằng pháp lý do các vấn đề cấp phép có thể :-)
UPDATE2: mã này sẽ có khả năng được sử dụng trong EJB môi trường, do đó, nó thích hợp hơn không để sinh ra các chủ đề bổ sung hoặc sử dụng các công cụ như thế.
interface Singleton
{
void init() throws SingletonException;
}
public class SingletonFactory
{
private static ConcurrentMap<String, AtomicReference<? extends Singleton>> CACHE =
new ConcurrentHashMap<String, AtomicReference<? extends Singleton>>();
public static <T extends Singleton> T getSingletonInstance(Class<T> clazz)
throws SingletonException
{
String key = clazz.getName();
if (CACHE.containsKey(key))
{
return readEventually(key);
}
AtomicReference<T> ref = new AtomicReference<T>(null);
if (CACHE.putIfAbsent(key, ref) == null)
{
try
{
T instance = clazz.newInstance();
instance.init();
ref.set(instance); // ----- (1) -----
return instance;
}
catch (Exception e)
{
throw new SingletonException(e);
}
}
return readEventually(key);
}
@SuppressWarnings("unchecked")
private static <T extends Singleton> T readEventually(String key)
{
T instance = null;
AtomicReference<T> ref = (AtomicReference<T>) CACHE.get(key);
do
{
instance = ref.get(); // ----- (2) -----
}
while (instance == null);
return instance;
}
}
Tôi không hoàn toàn chắc chắn về các dòng (1) và (2). Tôi biết rằng đối tượng được tham chiếu được khai báo là trường biến động trong AtomicReference
và do đó các thay đổi được thực hiện tại dòng (1) sẽ hiển thị ngay lập tức tại dòng (2) - nhưng vẫn còn một số nghi ngờ ...
Khác hơn thế - tôi nghĩ sử dụng ConcurrentHashMap
giải quyết nguyên tử của việc đưa khóa mới vào bộ nhớ cache.
Các bạn có thấy bất kỳ mối quan tâm nào với phương pháp này không? Cảm ơn!
PS: tôi biết về tĩnh lớp người giữ thành ngữ - và tôi không sử dụng nó do ExceptionInInitializerError
(mà bất kỳ ngoại lệ ném trong instantiation singleton được gói vào) và tiếp theo NoClassDefFoundError
mà không phải là điều mà tôi muốn bắt . Thay vào đó, tôi muốn tận dụng lợi thế của ngoại lệ kiểm tra chuyên dụng bằng cách bắt nó và xử lý nó một cách duyên dáng hơn là phân tích cú pháp dấu vết ngăn xếp của EIIR hoặc NCDFE.
Cảm ơn! Lib bên thứ 3 không phải là một lựa chọn trong trường hợp của tôi ... – anenvyguest