1. Pendahuluan
Dalam artikel ini, mari kita lihat kafein - perpustakaan cache Java berkinerja tinggi.
Salah satu perbedaan mendasar antara cache dan peta adalah bahwa cache dapat mendaur ulang item yang disimpan.
Kebijakan daur ulang adalah untuk menghapus objek pada waktu yang ditentukan. Strategi ini secara langsung mempengaruhi laju hit cache - fitur penting dari perpustakaan cache.
Kafein memberikan laju hit yang hampir optimal karena penggunaan strategi daur ulang tinylfu jendela.
2. Ketergantungan
Kita perlu menambahkan ketergantungan kafein di pom.xml:
<dependency> <GroupId> com.github.ben-manes.caffeine </groupId> <ArtifactId> kafein </artifactid> <version> 2.5.5 </version> </dependency>
Anda dapat menemukan versi terbaru dari kafein di Maven Central.
3. Isi cache
Mari kita lihat tiga strategi pengisian cache kafein: manual, pemuatan sinkron, dan pemuatan asinkron.
Pertama, kami menulis kelas untuk tipe nilai yang akan disimpan dalam cache:
Class DataObject {Private Final String Data; Private Static Int ObjectCounter = 0; // Konstruktor Standar/Getters Public Static DataObject GET (Data String) {ObjectCounter ++; mengembalikan DataObject baru (data); }}3.1. Pengisian manual
Dalam strategi ini, kami secara manual memasukkan nilainya ke dalam cache sebelum mengambilnya.
Mari kita inisialisasi cache:
Cache <String, DataObject> cache = caffeine.newBuilder () .ExpireAFterWrite (1, TimeUnit.minutes) .Maximumsize (100) .build ();
Sekarang kita dapat menggunakan metode getIfpresent untuk mendapatkan beberapa nilai dari cache. Jika nilai ini tidak ada di cache, metode ini mengembalikan nol:
String key = "a"; dataObject DataObject = cache.getIfpresent (key); AssertNull (DataObject);
Kita dapat menggunakan metode put untuk mengisi cache secara manual:
cache.put (key, DataObject); DataObject = Cache.GetIfPresent (key); AssertNotnull (DataObject);
Kami juga dapat menggunakan metode GET untuk mendapatkan nilai, yang melewati fungsi dengan kunci parameter sebagai parameter. Jika kunci tidak ada dalam cache, fungsi akan digunakan untuk memberikan nilai fallback, yang dimasukkan ke dalam cache setelah perhitungan:
dataObject = cache .get (tombol, k -> dataObject.get ("data untuk A")); AssertNotnull (DataObject); assertequals ("data untuk", dataObject.getData ());Metode GET dapat melakukan perhitungan secara atom. Ini berarti Anda hanya melakukan perhitungan sekali - bahkan jika beberapa utas meminta nilai pada saat yang sama. Inilah sebabnya mengapa menggunakan GET lebih baik daripada GetIfpresent.
Terkadang kita perlu secara manual membatalkan beberapa nilai yang di -cache:
cache.invalidate (key); dataObject = cache.getIfpresent (key); AssertNull (DataObject);
3.2. Pemuatan sinkron
Metode pemuatan cache ini menggunakan metode GET dengan strategi manual yang mirip dengan fungsi yang digunakan untuk menginisialisasi nilai. Mari kita lihat bagaimana menggunakannya.
Pertama, kita perlu menginisialisasi cache:
LoadingCache <String, DataObject> cache = caffeine.newBuilder () .Maximumsize (100) .ExpireAFterWrite (1, TimeUnit.Minutes) .Build (K -> DataObject.get ("Data untuk" + K));Sekarang kita dapat menggunakan metode GET untuk mengambil nilai:
DataObject DataObject = Cache.get (key); AssertNotnull (DataObject); assertequals ("data untuk" + tombol, dataObject.getData ());Kami juga dapat menggunakan metode GetAll untuk mendapatkan satu set nilai:
Peta <String, DataObject> dataObjectMap = cache.getall (arrays.aslist ("a", "b", "c")); assertequals (3, DataObjectMap.size ());Ambil nilai dari fungsi inisialisasi backend yang mendasarinya diteruskan ke metode build. Ini memungkinkan penggunaan cache sebagai fasad utama dari nilai mengakses.
3.3. Pemuatan asinkron
Kebijakan ini melakukan hal yang sama seperti sebelumnya, tetapi melakukan operasi secara tidak sinkron dan mengembalikan FuteableFuture yang berisi nilai:
Asyncloadingcache <string, dataObject> cache = caffeine.newbuilder () .maximumsize (100) .ExpireAFterWrite (1, TimeUnit.Minutes) .buildasync (K -> DataObject.get ("Data untuk" + K));Kita dapat menggunakan metode GET dan GetAll dengan cara yang sama, dengan mempertimbangkan bahwa mereka mengembalikan FuteableFuture:
String key = "a"; cache.get (key) .tHenAccept (dataObject -> {assertNotnull (dataObject); assertequals ("data untuk" + key, dataObject.getData ());}); cache.getall (arrays.aslist ("a", "b", "c"))) .tenAccept (DataObjectMap -> Assertequals (3, DataObjectMap.size ()));CompleteFuture memiliki banyak API yang berguna, dan Anda bisa mendapatkan lebih banyak di artikel ini.
4. Nilai pemulihan
Kafein memiliki tiga strategi pemulihan nilai: berbasis ukuran, berbasis waktu, dan berbasis referensi.
4.1. Daur ulang berdasarkan ukuran
Metode daur ulang ini mengasumsikan bahwa daur ulang terjadi ketika batas ukuran cache yang dikonfigurasi terlampaui. Ada dua cara untuk mendapatkan ukuran: Hitung objek di cache, atau mendapatkan berat.
Mari kita lihat cara menghitung objek dalam cache. Ketika cache diinisialisasi, ukurannya sama dengan nol:
LoadingCache <String, DataObject> cache = caffeine.newBuilder () .maximumsize (1) .build (k -> dataObject.get ("Data untuk" + k)); assertequals (0, cache.estimatedSize ());Ketika kami menambahkan nilai, ukurannya meningkat secara signifikan:
cache.get ("a"); assertequals (1, cache.esttimatedSize ());Kita dapat menambahkan nilai kedua ke cache, yang menyebabkan nilai pertama dihapus:
cache.get ("b"); cache.cleanup (); assertequals (1, cache.esttimatedSize ());Perlu disebutkan bahwa sebelum mendapatkan ukuran cache, kami memanggil metode pembersihan. Ini karena daur ulang cache dieksekusi secara tidak sinkron, dan pendekatan ini membantu menunggu daur ulang untuk diselesaikan.
Kami juga dapat melewati fungsi penimbangan untuk mendapatkan ukuran cache:
LoadingCache <String, DataObject> cache = caffeine.newbuilder () .Maximumweight (10) .Weighter ((K, V) -> 5) .build (K -> DataObject.get ("Data untuk" + K)); assertequals (0, cache.estimatedSize ()); cache.get ("a"); assertequals (1, cache.esttimatedSize ()); cache.get ("b"); assertequals (2, cache.estimatedSize ());Ketika berat melebihi 10, nilainya dihapus dari cache:
cache.get ("c"); cache.cleanup (); assertequals (2, cache.estimatedSize ());4.2. Berdasarkan Pemulihan Waktu
Strategi daur ulang ini didasarkan pada waktu kedaluwarsa entri, dan ada tiga jenis:
Mari kita konfigurasikan kebijakan kedaluwarsa pasca-akses menggunakan metode kedaluwarsa:
LoadingCache <String, DataObject> cache = caffeine.newBuilder () .ExpireAFTERACCESS (5, TimeUnit.minutes) .build (k -> dataObject.get ("Data untuk" + k));Untuk mengonfigurasi kebijakan kedaluwarsa pasca-tulisan, kami menggunakan metode kedaluwarsa:
cache = caffeine.newbuilder () .ExpireAFterWrite (10, TimeUnit.Seconds) .weakkeys () .weakValues () .build (k -> dataObject.get ("data untuk" + k));Untuk menginisialisasi kebijakan khusus, kita perlu mengimplementasikan antarmuka kedaluwarsa:
cache = caffeine.newbuilder (). ExpireAfter (baru Expiry <String, DataObject> () {@Override Public Long ExpireAfterCreate (Kunci String, Nilai DataObject, Long Currenttime) {return value.getData (). Panjang () * 1000;} @Override Public Expirate (). Panjang () * 1000;} @Override Public Expirate (). CurrentDuration;} @Override Panjang Panjang Kedaluwarsa (Kunci String, Nilai DataObject, Long Currenttime, Long CurrentDuration) {Return CurrentDuration;4.3. Daur ulang berdasarkan referensi
Kami dapat mengonfigurasi cache untuk mengaktifkan pengumpulan sampah dari nilai kunci yang di -cache. Untuk melakukan ini, kami mengonfigurasi kunci dan nilai sebagai referensi yang lemah, dan kami hanya dapat mengonfigurasi referensi lunak untuk pengumpulan sampah.
Ketika tidak ada referensi yang kuat untuk objek, menggunakan Lemah Lemah dapat memungkinkan pengumpulan objek sampah. Softreference memungkinkan objek untuk dikumpulkan oleh sampah berdasarkan kebijakan global yang paling tidak digunakan secara global. Untuk detail lebih lanjut tentang kutipan Java, lihat di sini.
Kita harus mengaktifkan setiap opsi menggunakan caffeine.weakkeys (), caffeine.weakvalues (), dan caffeine.softValues ():
LoadingCache <String, DataObject> cache = caffeine.newBuilder () .ExpireAFterWrite (10, TimeUnit.Seconds) .weakkeys () .weakValues () .build (k -> dataObject.get ("data untuk" + k)); cache = caffeine.newbuilder () .ExpireAFterWrite (10, TimeUnit.Seconds) .softValues () .build (k -> dataObject.get ("Data untuk" + k));5. Refresh
Cache dapat dikonfigurasi untuk secara otomatis menyegarkan entri setelah periode waktu yang ditentukan. Mari kita lihat cara menggunakan metode RefreshAfterWrite:
Caffeine.newbuilder () .refreshafterwrite (1, timeunit.minutes) .build (k -> dataObject.get ("data untuk" + k));Di sini kita harus memahami perbedaan antara kedaluwarsa dan penyegaran. Ketika entri kedaluwarsa diminta, eksekusi akan diblokir sampai fungsi build menghitung nilai baru.
Namun, jika entri dapat disegarkan, cache mengembalikan nilai lama dan memuat ulang nilainya secara tidak sinkron.
6. Statistik
Kafein memiliki cara untuk merekam penggunaan cache:
LoadingCache <String, DataObject> cache = caffeine.newbuilder () .maximumsize (100) .recordstats () .build (k -> dataObject.get ("data untuk" + k)); cache.get ("a"); cache.get ("a"); assertequals (1, cache.stats (). hitcount ()); assertequals (1, cache.stats (). misscount ());Kami juga dapat melewati pemasok RecordStats untuk membuat implementasi Statscounter. Objek ini didorong setiap perubahan terkait statistik.
7. Kesimpulan
Dalam artikel ini, kami akrab dengan Perpustakaan Cafeine Cache Java. Kami melihat cara mengkonfigurasi dan mengisi cache, dan bagaimana memilih kebijakan kedaluwarsa atau penyegaran yang sesuai berdasarkan kebutuhan kami.
Kode sumber untuk contoh dalam artikel ini dapat ditemukan di GitHub.
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.