2010-11-09 33 views
6

Vì vậy, đây là vấn đề tôi đang cố gắng để giải quyết - Tôi có một đối tượng với hai lĩnh vực số nguyên mà tôi muốn để cacheehcache - sử dụng một danh sách <Integer> như giá trị bộ nhớ cache

public class MyObject { 
    int x; 
    int y; 
    .... 
} 

Bây giờ lĩnh vực x là gì Tôi chủ yếu là phù hợp trên - nhưng có thể có bản sao trong trường hợp tôi muốn rơi trở lại vào lĩnh vực thứ hai (để this.x = that.x và this.y = that.y). y chỉ có thể là 25 giá trị khác biệt. Bây giờ tôi biết tôi chỉ có thể kết hợp hai như một String và sử dụng nó như là khóa bộ nhớ cache, nhưng sau đó tôi sẽ phải thử x+[25 possible values] để thực sự xác định nếu nó không có trong bộ nhớ cache làm cho bộ nhớ cache nhớ rất tốn kém. Tôi đã nghĩ đến việc cố gắng lưu trữ List<Integer> làm giá trị bộ nhớ cache cho trường x và sau đó nếu chúng nhiều hơn một, hãy lặp lại danh sách và tìm kiếm kết quả phù hợp trên y.

Bây giờ nếu tôi sử dụng ConcurrentList (hoặc Tập hợp nếu tôi quan tâm đến các bản sao - cho phép bỏ qua điều đó bây giờ) nhiều chủ đề có thể thêm vào và sau đó đưa nó trở lại bộ đệm không có điều kiện chủng tộc? Có thể là Ehcache có thể trả về hai đối tượng danh sách khác nhau cho hai luồng và sau đó khi chúng thêm giá trị mới của chúng vào danh sách và cố gắng đưa nó trở lại bộ đệm, tôi có thể nhận được kết quả không xác định? Bạn có thấy cách xây dựng bộ đệm ẩn này tốt hơn không?

EDIT: Tôi đánh giá cao các câu trả lời bên dưới, nhưng mọi người dường như thiếu điểm chính. Điều này có hiệu quả không? Có thể Ehcache thực sự trả về hai đối tượng khác nhau cho cùng một cacheKey (nói nếu đối tượng nằm trên đĩa trong suốt cuộc gọi và nó được tuần tự hóa nó hai lần, một lần cho mỗi cuộc gọi).

+0

Có lý do nào khiến bạn không thể sử dụng băm làm khóa không? – Falmarri

+0

Như tôi đã nói trong câu hỏi đó có nghĩa là cho bất kỳ giá trị nhất định của x tôi sẽ phải kiểm tra bộ nhớ cache có thể 25 lần để thực sự biết nó không có trong bộ nhớ cache. Tôi muốn khớp trên x bất kể giá trị của y - nhưng nếu có nhiều x thì giá trị tốt nhất của y. – Gandalf

+0

Có thể có một giá trị được thêm hai lần bằng phương pháp bạn đã đề cập. Thay vì sử dụng ConcurrentMap. –

Trả lời

4

Đó là hoàn toàn có thể là bạn sẽ có được hai trường hợp khác nhau của Danh sách của bạn (hoặc của bất kỳ Serializable)! Hãy thử điều này:

public static void main(final String[] args) throws Exception { 
    final Cache cache = CacheManager.getInstance().getCache("smallCache"); 

    final List<String> list = new ArrayList<String>(); 
    cache.put(new Element("A", list)); 

    /* We put in a second element. Since maxElementsInMemory="1", this means 
    * that "A" will be evicted from memory and written to disk. */ 
    cache.put(new Element("B", new ArrayList<String>())); 
    Thread.sleep(2000); // We need to wait a bit, until "A" is evicted. 

    /* Imagine, the following happens in Thread 1: */ 
     final List<String> retrievedList1 = 
        (List<String>) cache.get("A").getValue(); 
     retrievedList1.add("From Thread 1"); 

    /* Meanwhile, someone puts something in the cache: */ 
     cache.put(new Element("C", new ArrayList<String>())); 

    Thread.sleep(2000); // Once again, we wait a bit, until "A" is evicted. 

    /* Now the following happens in Thread 2: */ 
     final List<String> retrievedList2 = 
        (List<String>) cache.get("A").getValue(); 
     retrievedList2.add("From Thread 2"); 
     cache.put(new Element("A", retrievedList2)); 

    /* Meanwhile in Thread 1: */  
     cache.put(new Element("A", retrievedList1)); 

    /* Now let's see the result: */ 
    final List<String> resultingList = 
         (List<String>) cache.get("A").getValue(); 
    for (final String string : resultingList) { 
     System.out.println(string); 
    } /* Prints only "From Thread 1". "From Thread 2" is lost. 
       But try it with maxElementsInMemory="3", too!! */ 

    CacheManager.getInstance().shutdown(); 
} 

tôi đã sử dụng sau trong ehcache.xml:

<cache name="smallCache" 
     maxElementsInMemory="1" 
     eternal="true" 
     overflowToDisk="true" 
     diskPersistent="true" 
     maxElementsOnDisk="200" 
     memoryStoreEvictionPolicy="LRU" 
     transactionalMode="off" 
     > 
</cache> 

Một giải pháp có thể được sử dụng Explicit Locking, mà dường như có sẵn cho độc lập (không nung) cache, quá (kể từ ehcache 2.1).

Một giải pháp khác là chỉ có một chuỗi có thể sửa đổi Danh sách. Nếu bạn có nhiều chủ đề có thể sửa đổi nó và bạn không sử dụng khóa trên bộ nhớ cache, thì bạn có thể nhận được chính xác kết quả chưa xác định mà bạn đã mô tả!

+0

Điều đó không hiển thị bộ nhớ cache trả lại hai bản sao khác nhau của danh sách, cho thấy bạn đang giữ một và sau đó đọc một từ đĩa. – Gandalf

+0

@Gandalf: Chỉ cần làm điều tương tự hai lần: Thực hiện lệnh flush khác() + Thread.sleep() và sau đó truy xuất lại. Bạn sẽ nhận được hai bản sao khác nhau. –

+0

@Gandalf: Tôi đã chỉnh sửa ví dụ một số chi tiết (mô phỏng nhiều luồng) để làm cho nó hoàn toàn rõ ràng, cách vấn đề có thể xảy ra. Bây giờ đã lâu hơn một chút, nhưng nó cho thấy chính xác những gì bạn sợ trong câu hỏi của bạn. Hãy thử nó với maxElementsInMemory = "3", quá, và thấy sự khác biệt! –

2

Tôi có một cách tiếp cận khác cho bạn, mà tôi vừa đọc trong một bài viết về tìm kiếm theo phạm vi địa lý.

Đặt hai cặp khóa-giá trị trong bộ nhớ cache: Một cặp chỉ có x làm khóa và một với cả x và y làm khóa. Khi bạn tìm trong bộ nhớ cache, hãy tìm khóa x-và-y trước. Nếu nó ở đó, bạn đã tìm thấy một trận đấu hoàn hảo. Nếu nó không có ở đó, hãy tìm khóa x và có thể tìm thấy kết hợp với giá trị y khác.

+0

+1 cho tư duy sáng tạo - giống như cách tiếp cận –

+1

Bộ nhớ cache có khoảng 15 triệu đối tượng - vì vậy tôi không muốn phát triển nó lên 30 triệu trừ khi không có cách nào khác. Tôi sẽ giữ điều này trong tâm trí mặc dù. – Gandalf

+0

Cũng như thế nào bộ nhớ cache chỉ sử dụng 'x' như là chìa khóa thậm chí làm việc kể từ khi tôi có thể có nhiều đối tượng với cùng một giá trị 'x' (nhưng khác nhau 'y'). – Gandalf

0

Bạn có thể sử dụng Bản đồ chứa tập hợp được sắp xếp làm giá trị. Bản đồ đầu tiên có thể lập chỉ mục trên X và sau đó bạn có thể chọn phần tử đầu tiên từ tập hợp được sắp xếp nơi sắp xếp dựa trên Y.

Tôi đoán rằng bộ sưu tập của google có rất nhiều thứ gọn gàng mà bạn có thể sử dụng, ví dụ: SortedSetMultimap:

http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/SortedSetMultimap.html

1

tôi sẽ tạo ra một phương pháp để có được giá trị cho đối tượng của bạn. Sử dụng một semaphore để hạn chế quyền truy cập vào phương thức (hoặc sử dụng đồng bộ).

Trong phương pháp của bạn, hãy kiểm tra các kết quả phù hợp với X và nếu điều đó trả về nhiều kết quả, văn bản cho kết quả khớp XY.

Khi đối tượng nằm ngoài bộ đệm, mọi sửa đổi đối tượng cũng sẽ sửa đổi đối tượng trong bộ nhớ cache (vì chúng đang trỏ đến cùng một thể hiện).

Nếu bạn muốn cực kỳ cẩn thận, hãy sử dụng các phương thức được đồng bộ hóa để nhận/đặt các biến thành viên trong MyObject và bao gồm khóa là trường hợp MyObject.

public void setX(int x) { 
    synchronized(this) { 
     this.x = x; 
    } 
} 
0
  • Tạo một lớp chính của xy, tức là.class Key { int x,y }
  • thực hiện một thao tác so sánh riêng cho bạn "đặt hàng từ vựng" trên xy,
  • đặt nó vào một Map<Key,Value>
Các vấn đề liên quan