(sơ bộ lưu ý: có lẽ đây là phù hợp hơn cho codereview?)Các cách để cải thiện mã đó chỉ sử dụng JDK (6) các lớp được cung cấp? (Đồng thời, an toàn thread)
EDITAnswer to self; Tôi tin rằng câu trả lời này bao gồm tất cả các nhu cầu/vấn đề của tôi, nhưng tất nhiên, nhận xét được hoan nghênh. Câu hỏi gốc bên dưới để tham khảo.
Xin chào,
Quan tâm ở đây là phương pháp .getSources()
. Phương thức này có nghĩa là trả về một danh sách các nguồn tin nhắn cho một Locale
nhất định.
Hai cấu trúc dữ liệu trung tâm cho phương pháp này là sources
và failedLookups
, xem mã cho nhận xét.
thực hiện đặc biệt này của .getSources()
chỉ bao giờ có thể trở lại hoặc là một danh sách trống hoặc một danh sách phần tử duy nhất, tùy thuộc vào tryAndLookup()
phương pháp mà nguyên mẫu là:
protected abstract MessageSource tryAndLookup(final Locale locale)
throws IOException;
Ngay bây giờ, logic của mã này là như sau:
- nếu nguồn tin nhắn cho ngôn ngữ đó đã được tra cứu thành công, nó sẽ được trả về;
- từ thời điểm này trở đi, không có tra cứu nào được thực hiện; tuy nhiên không biết liệu điều này có nghĩa là một lần tra cứu trước đó đã được thực hiện: kiểm tra tập hợp tra cứu không thành công, nếu ngôn ngữ tra cứu nằm trong đó, đó là lỗi đã biết, trả về danh sách trống;
- bây giờ, tình huống đã biết là tra cứu ngôn ngữ này thực sự chưa bao giờ được thực hiện: thực hiện nó; tùy thuộc vào kết quả của phương pháp
tryAndLookup
, ghi lại thành công hoặc thất bại.
Bây giờ, tại sao tôi đi đến độ dài như vậy: Tôi không kiểm soát được tryAndLookup()
; có thể mất một lượng thời gian để thực thi trước khi trả về một nguồn hợp lệ hoặc không thành công. Kết quả là, tôi không muốn sử dụng khóa thô hoặc khối synchronized
.
/**
* Set of locales known to have failed lookup.
*
* <p>When a locale is in this set, it will not attempt to be reloaded.</p>
*/
private final Set<Locale> lookupFailures
= new CopyOnWriteArraySet<Locale>();
/**
* Set of message sources successfully looked up
*
* <p>When a source is in there, it is there permanently for now.</p>
*/
private final ConcurrentMap<Locale, MessageSource> sources
= new ConcurrentHashMap<Locale, MessageSource>();
@Override
protected final List<MessageSource> getSources(final Locale locale)
{
MessageSource source = sources.get(locale);
/*
* If found, return it
*/
if (source != null)
return Arrays.asList(source);
/*
* If it is a registered failure, return the empty list
*/
if (lookupFailures.contains(locale))
return Collections.emptyList();
/*
* OK, try and look it up. On success, register it in the sources map.
* On failure, record the failure an return the empty list.
*/
try {
source = tryAndLookup(locale);
sources.putIfAbsent(locale, source);
// EDIT: fix for bug pinpointed by JBNizet
// was:
// return Arrays.asList(source);
// now is:
return Arrays.asList(sources.get(locale));
} catch (IOException ignored) {
lookupFailures.add(locale);
return Collections.emptyList();
}
}
Câu hỏi của tôi ở đây có ba điểm:
- Tôi cố tình hạn chế bản thân mình đến các lớp học chỉ dành cho JDK; Tôi đã chọn
ConcurrentHashMap
làm triển khaiConcurrentMap
vàCopyOnWriteArraySet
làm triển khai an toàn threadSet
; từ javadoc, đây là những điều tốt nhất tôi có thể tìm thấy. Nhưng tôi có bị lừa dối ở đâu đó không? - I nghĩ mã này là cuối cùng là chủ đề an toàn; một số trường hợp góc có thể dẫn đến tra cứu được thực hiện nhiều hơn một lần ví dụ, nhưng sau đó đây là lý do tại sao tôi làm
.putIfAbsent()
; ngay bây giờ tôi đã luôn sử dụng và tin cậy, sốLoadingCache
của Guava cho mục đích lưu vào bộ nhớ cache và đây là lần đầu tiên tôi bước ra khỏi lãnh thổ này; mã này có thực sự an toàn không? - mã này có lỗi nghiêm trọng: nhiều hơn một luồng có thể đang thực thi
tryAndLookup()
cùng một lúc ... Giải pháp nào tồn tại để phương pháp này được thực thi chỉ một lần cho mỗi lần tra cứu?
Với Java 6 là ở cuối dòng, có lẽ đã đến lúc sử dụng Java 7.;) Bạn có biết bạn cần lưu vào bộ nhớ cache các ngôn ngữ như thế này không? Đây có phải là thứ bạn tra cứu hàng triệu lần mỗi giây chỉ vài nghìn lần mỗi giây? –
Vâng, nó có thể được chính thức ở cuối dòng, nhưng nó vẫn là phiên bản được sử dụng rộng rãi nhất hiện có:/Như để tra cứu tần số, nó là khá theo thứ tự của hàng chục lần một giây, hàng trăm ở mức tối đa .. Tôi chỉ nhằm mục đích có mã chống đạn cuối cùng;) – fge
Đối với một vài trăm lần mỗi giây, tôi sẽ có một khối đồng bộ đồng bộ. Bạn sẽ rất hiếm khi có hai chủ đề truy cập nó cùng một lúc. Tôi thích giữ mọi thứ đơn giản trừ khi bạn biết có một lý do chính đáng để làm cho mọi thứ trở nên phức tạp hơn. –