Kata pengantar
Ini cukup menganggur selama periode ini, jadi saya melihat kode sumber JDK. Seorang insinyur pengembangan senior umum dapat meningkatkan dirinya dengan membaca beberapa kode sumber. Artikel ini merangkum beberapa "tips kecil" dalam kode sumber JDK dan membagikannya untuk referensi dan pembelajaran Anda. Saya tidak akan banyak bicara di bawah ini, mari kita lihat perkenalan yang terperinci bersama.
1 i ++ vs i--
Baris 985 kode sumber string, dalam metode yang sama
while (n-! = 0) {if (v1 [i]! = v2 [i]) mengembalikan false; i ++; }Kode ini digunakan untuk menilai apakah string itu sama, tetapi ada hal aneh yang menggunakan i-! = 0 untuk membuat penilaian. Bukankah kita biasanya menggunakan I ++? Mengapa menggunakan i--? Dan jumlah siklusnya sama. Alasannya adalah bahwa akan ada satu instruksi lagi setelah kompilasi:
I-- Operasi itu sendiri akan mempengaruhi CPSR (register status program saat ini). Bendera umum untuk CPSR adalah N (hasilnya negatif), z (hasilnya adalah 0), C (carry), dan O (overflow). i> 0, dapat secara langsung dinilai oleh bendera z.
Operasi I ++ juga akan mempengaruhi CPSR (register status program saat ini), tetapi hanya mempengaruhi bendera O (dengan overflow), yang tidak akan membantu dalam penilaian i <n. Oleh karena itu, diperlukan instruksi perbandingan tambahan, yang berarti bahwa satu instruksi lagi harus dieksekusi untuk setiap loop.
Sederhananya, dibandingkan dengan 0, akan ada satu instruksi yang lebih sedikit. Karena itu, daur ulang I--, high-end, atmosfer dan kelas atas.
2 Variabel Anggota vs Variabel Lokal
Kode sumber JDK hampir menggunakan variabel lokal untuk menerima variabel anggota dalam metode apa pun, misalnya
compareto int publik (string anotherstring) {int len1 = value.length; int len2 = anotherstring.value.length;Karena variabel lokal diinisialisasi dalam tumpukan utas metode, sedangkan variabel anggota diinisialisasi dalam memori heap, jelas yang pertama lebih cepat, jadi kami mencoba menghindari menggunakan variabel anggota secara langsung dalam metode ini, tetapi sebaliknya menggunakan variabel lokal.
3 dengan sengaja memuat ke register && menempatkan operasi yang memakan waktu di luar kunci
Di ConcurrenthashMap, pengoperasian segmen kunci sangat menarik. Ini bukan kunci langsung, tetapi mirip dengan kunci spin. Berulang kali mencoba untuk mendapatkan kunci. Selama proses memperoleh kunci, itu akan melintasi daftar yang ditautkan, sehingga data akan dimuat ke dalam cache register terlebih dahulu, menghindari kenyamanan dalam proses kunci. Pada saat yang sama, pengoperasian menghasilkan objek baru juga ditempatkan di luar kunci untuk menghindari operasi yang memakan waktu di kunci
final v put (K key, int hash, v Value, boolean onlyifabsent) { /** Sebelum menulis ke segmen ini, Anda perlu mendapatkan kunci eksklusif segmen terlebih dahulu. Ini bukan untuk memaksa kunci (), tetapi untuk mencoba*/ hashentry <k, v> node = trylock ()? null: scanandlockforput (kunci, hash, nilai); Kode Sumber ScanAndlockForput ()
hashentry pribadi <k, v> scanandlockforput (K key, int hash, value v) {hashentry <k, v> pertama = entryforhash (ini, hash); Hashentry <k, v> e = pertama; Hashentry <k, v> node = null; int retries = -1; // negatif saat menemukan node // looping untuk mendapatkan kunci sementara (! trylock ()) {hashentry <k, v> f; // to recheck first below if (retries < 0) { if (e == null) { if (node == null) // speculatively create node //The hash bit has no value, create a new object, and no need to go to the lock of the put() method to create a new node = new HashEntry<K,V>(hash, key, value, null); retries = 0; } // Kunci posisi hash adalah sama, merosot menjadi kunci spin lain jika (key.equals (e.key)) retries = 0; else // retries dapat secara otomatis membaca daftar yang ditautkan ke cache e = e.next; } // Ketika coba lagi> 0, itu menjadi kunci putaran. Tentu saja, jika jumlah retries melebihi max_scan_retries (inti tunggal 1 multi-core 64), maka jangan merebutnya, masukkan antrian pemblokiran dan tunggu kunci // lock () adalah metode pemblokiran sampai kembali setelah mendapatkan kunci, jika tidak akan digantung lebih dari (++ retries> max_sscan_retries) {lock) {) {lock) {) merusak; } lain jika ((coba lagi & 1) == 0 && // Ada masalah besar saat ini, yaitu elemen baru masuk ke daftar yang ditautkan dan menjadi header baru // jadi strateginya di sini adalah setara dengan melalui metode scanandlockforput lagi (f = entryforhash (ini, hash))! = First) {e = first = f; // Traverse jika entri diubah retries = -1; }} return node;} 4 Anda dapat menggunakannya terlebih dahulu untuk menentukan kesetaraan objek ==
Saat menilai apakah objeknya sama, Anda dapat menggunakan == terlebih dahulu, karena == langsung membandingkan alamat, yang sangat cepat, sementara sama akan membandingkan nilai objek terbanyak, yang relatif lambat. Jadi jika memungkinkan, Anda dapat menggunakan A == B || A.Equals (b) Untuk membandingkan apakah objek itu sama.
5 Tentang sementara
Transien digunakan untuk mencegah serialisasi, tetapi array internal dalam kode sumber hashmap didefinisikan sebagai sementara.
/*** Tabel, diubah ukurannya seperlunya. Panjang harus selalu menjadi kekuatan dua. */ entri transien <k, v> [] tabel = (entri <k, v> []) kosong_table;
Maka tidak akan pasangan nilai kunci di dalam tidak dapat diserialisasi? Bukankah tidak mungkin untuk mentransmisikan menggunakan hashmap di jaringan? Faktanya, tidak.
Java 2 yang efektif, item75, Joshua disebutkan:
Misalnya, pertimbangkan kasus tabel hash. Fisiknya
Representasi adalah urutan ember hash yang berisi nilai kunci
entri. Bucket tempat entri berada adalah fungsi dari hash
kode kuncinya, yang secara umum, dijamin sama
Dari implementasi JVM hingga implementasi JVM. Faktanya, itu tidak bahkan
Dijamin sama dari lari ke lari. Oleh karena itu, menerima
Formulir serial default untuk tabel hash akan menjadi serius
serangga. Membuat serialisasi dan deserialisasi meja hash dapat menghasilkan
objek yang invariannya sangat korup.
Bagaimana cara memahami? Lihatlah hashmap.get ()/put () untuk mengetahui bahwa membaca dan menulis peta didasarkan pada objek.hashCode () untuk menentukan ember mana yang harus dibaca/ditulis. Object.HashCode () adalah metode asli, yang mungkin berbeda dalam JVM yang berbeda.
Misalnya, simpan entri ke hashmap, kunci adalah string "string". Dalam program Java pertama, hashcode () dari "string" adalah 1, dan bucket nomor 1 disimpan; Dalam program Java kedua, hashcode () dari "string" mungkin 2, dan bucket nomor 2 disimpan. Jika serialisasi default digunakan (tabel entri [] tidak memerlukan transien), maka setelah hashmap ini mengimpor program Java kedua melalui serialisasi dari program Java pertama, distribusi memorinya sama, yang salah.
Misalnya, jika Anda menyimpan entri pasangan nilai kunci ke hashmap, key = "fang laosi", dalam program java pertama, kode hashcode () dari "fang laosi" adalah 1, dan tabel [1] disimpan. OK, sekarang diteruskan ke program JVM lain, HashCode () dari "Fang Laosi" mungkin 2, jadi Anda pergi ke Tabel [2] untuk mendapatkannya, dan hasilnya tidak ada.
ReadObject dan WriteObject HashMap saat ini digunakan untuk mengeluarkan/memasukkan konten dan meregenerasi hashmap.
6 Jangan gunakan char
Char dikodekan dalam UTF-16 di Java, dan 2 byte, dan 2 byte tidak dapat mewakili semua karakter. 2 byte disebut BMP, dan yang lain disebut pengganti tinggi dan pengganti rendah untuk membentuk karakter 4-byte yang diwakili oleh penulisan. Misalnya, IndexOf dalam Kode Sumber String:
// Berikut ini adalah int untuk menerima char untuk memfasilitasi penilaian rentang indeks int int (int ch, int fromIndex) {final int max = value.length; if (fromIndex <0) {fromIndex = 0; } lain if (fromIndex> = max) {// Catatan: fromIndex mungkin dekat -1 >>> 1. kembali -1; } // Dalam rentang BMP if (ch <character.min_supplementary_code_point) {// menangani sebagian besar kasus di sini (CH adalah titik kode BMP atau nilai // nilai negatif (titik kode tidak valid)) char akhir [] nilai = ini.value; untuk (int i = fromIndex; i <max; i ++) {if (value [i] == ch) {return i; }} return -1; } else {// Sebaliknya, pergi ke metode penilaian empat-byte pengembalian indeks dari tupai (ch, fromIndex); }}Oleh karena itu, Java's Char hanya dapat mewakili karakter parsial BMP di UTF16. Untuk CJK (Cina, Jepang, dan Korea Selatan Unified Ideogram) parsial set karakter yang diperluas, mereka tidak dapat diungkapkan.
Misalnya, Char tidak dapat diwakili kecuali untuk bagian EXT-A pada gambar di bawah ini.
Selain itu, ada pepatah lain bahwa Anda harus menggunakan char. Jangan gunakan string untuk kata sandi. String adalah konstan (yaitu, tidak dapat diubah setelah pembuatan), dan akan disimpan di kolam konstan. Jika proses lain dapat membuang memori proses, kata sandi akan bocor karena kumpulan konstan dibuang, dan char [] dapat menulis informasi lain untuk diubah, yang berarti akan mengurangi risiko bocor kata sandi.
Tapi saya pribadi berpikir Anda bisa membuang ingatan. Bisakah char dapat mencegahnya? Kecuali jika string tidak didaur ulang di kolam konstan dan dibaca langsung dari kolam konstan oleh utas lain, itu mungkin sangat jarang.
Meringkaskan
Di atas adalah seluruh konten artikel ini. Saya berharap konten artikel ini memiliki nilai referensi tertentu untuk studi atau pekerjaan semua orang. Jika Anda memiliki pertanyaan, Anda dapat meninggalkan pesan untuk berkomunikasi. Terima kasih atas dukungan Anda ke wulin.com.