Apa itu kunci spin
Berbicara tentang kunci spin, kita perlu mulai dengan mekanisme kunci di bawah multi-threading. Karena beberapa sumber daya dalam lingkungan sistem multi-prosesor terbatas, mereka kadang-kadang memerlukan pengecualian timbal balik. Pada saat ini, mekanisme kunci akan diperkenalkan. Hanya proses yang memperoleh kunci yang dapat memperoleh akses sumber daya. Artinya, hanya satu proses yang dapat memperoleh kunci pada satu waktu untuk memasuki area kritisnya sendiri. Pada saat yang sama, dua atau lebih proses tidak dapat memasuki area kritis. Saat keluar dari area kritis, kunci akan dilepaskan.
Saat merancang algoritma Mutex, Anda selalu menghadapi situasi di mana Anda tidak memiliki kunci, yaitu, apa yang harus Anda lakukan jika Anda tidak mendapatkan kunci?
Biasanya ada 2 cara untuk menghadapinya:
Salah satunya adalah bahwa penelepon yang belum memperoleh kunci di sekitar sana untuk melihat apakah pemegang kunci spin telah melepaskan kunci. Ini adalah fokus artikel ini - spin lock. Dia tidak harus memblokir kota garis (tidak memblokir).
Cara lain adalah bahwa proses tanpa mendapatkan blok kunci itu sendiri (memblokir) dan terus menjalankan tugas lain pada utas, yang merupakan mutex (termasuk kunci built-in yang disinkronkan, reentrantlock, dll.).
perkenalan
CAS (Bandingkan dan bertukar), yaitu, perbandingan dan pertukaran, juga merupakan operasi inti yang mengimplementasikan apa yang biasanya kita sebut kunci spin atau kunci optimis.
Implementasinya sangat sederhana, yaitu membandingkan nilai yang diharapkan dengan nilai memori. Jika kedua nilai tersebut sama, ganti nilai memori dengan nilai yang diharapkan dan return true. Jika tidak, kembalikan salah.
Pastikan operasi atom
Teknologi apa pun muncul untuk menyelesaikan masalah spesifik tertentu. Masalah yang perlu dipecahkan CAS adalah untuk memastikan operasi atom. Apa itu operasi atom? Atom adalah yang terkecil dan tidak senonoh, dan operasi atom adalah operasi terkecil dan tidak senonoh. Dengan kata lain, setelah operasi dimulai, tidak dapat terganggu dan tahu bahwa operasi selesai. Dalam lingkungan multi-threaded, operasi atom adalah cara penting untuk memastikan keamanan utas. Misalnya, misalkan ada dua utas yang berfungsi dan ingin memodifikasi nilai tertentu. Ambil operasi pendakian diri sebagai contoh. Untuk melakukan operasi pendakian diri pada Integer I, tiga langkah dasar diperlukan:
1. Baca nilai saya saat ini;
2. Tambahkan 1 ke nilai I;
3. Tulis nilai i kembali ke memori;
Misalkan kedua proses membaca nilai saat ini dari i, dengan asumsi 0, pada saat ini, utas A menambahkan 1 ke I, Thread B juga menambahkan 1, dan akhirnya saya adalah 1, bukan 2. Ini karena operasi autoINCREMENT bukan operasi atom, dan tiga langkah yang dibagi dapat diganggu. Seperti pada contoh di bawah ini, untuk 10 utas, setiap utas melakukan operasi 10.000 I ++, nilai yang diharapkan adalah 100.000, tetapi sayangnya, hasilnya selalu kurang dari 100.000.
statis int i = 0; public static void add () {i ++; } private static class plus implement runnable {@Override public void run () {for (int k = 0; k <10000; k ++) {add (); }}} public static void main (string [] args) melempar interruptedException {thread [] threads = utas baru [10]; untuk (int i = 0; i <10; i ++) {threads [i] = utas baru (baru plus ()); utas [i] .start (); } untuk (int i = 0; i <10; i ++) {threads [i] .join (); } System.out.println (i); }Dalam hal ini, apa yang harus saya lakukan? Itu benar, mungkin Anda sudah memikirkannya, Anda dapat mengunci atau menggunakan implementasi yang disinkronkan, misalnya, memodifikasi metode add () untuk yang berikut:
public disinkronkan statis void add () {i ++; }Atau, operasi penguncian diimplementasikan, misalnya, menggunakan Reentrantlock (Reentrantlock).
kunci kunci statis pribadi = reentrantlock baru (); public static void add () {lock.lock (); i ++; lock.unlock (); } CAS mengimplementasikan spin lock
Karena operasi atom dapat diimplementasikan menggunakan kata kunci atau kata kunci yang disinkronkan, mengapa menggunakan CAS? Karena mengunci atau menggunakan kata kunci yang disinkronkan membawa kehilangan kinerja yang besar, saat menggunakan CA dapat mencapai penguncian yang optimis. Ini sebenarnya secara langsung menggunakan instruksi tingkat CPU, sehingga kinerjanya sangat tinggi.
Seperti disebutkan di atas, CAS adalah dasar untuk menerapkan kunci putaran. CAS menggunakan instruksi CPU untuk memastikan atomisitas operasi untuk mencapai efek kunci. Adapun putaran, juga sangat jelas untuk membaca makna literal. Jika Anda memutarnya sendiri, itu adalah loop. Secara umum diimplementasikan menggunakan loop tak terbatas. Dengan cara ini, operasi CAS dieksekusi dalam loop tak terbatas. Ketika operasi berhasil dan mengembalikan true, loop berakhir; Ketika salah, loop dieksekusi dan operasi CAS dilanjutkan sampai benar dikembalikan.
Faktanya, banyak tempat di JDK menggunakan CAS, terutama dalam paket java.util.concurrent, seperti CountdownLatch, Semaphore, Reentrantlock, dan Java.util.concurrent.atomic Paket. Saya percaya semua orang telah menggunakan atom*, seperti atomicboolean, atomicinteger, dll.
Di sini kami menganggap atomicboolean sebagai contoh, karena cukup sederhana.
Atomicboolean kelas publik mengimplementasikan java.io.serializable {private static final long serialversionuid = 4654671469794556979l; // setup untuk menggunakan unsafe.CompareAndsWapint untuk memperbarui final private static uncafe tidak aman = uncafe.getunsafe (); valueOffset panjang final statis pribadi; static {try {valueOffset = uncafe.objectFieldOffset (atomicboolean.class.getDeclaredField ("value")); } catch (Exception ex) {throw new error (ex); }} nilai int volatil privat; public final boolean get () {value return! = 0; } public final boolean compareEndset (boolean hare, pembaruan boolean) {int e = harapkan? 1: 0; int u = perbarui? 1: 0; return unsafe.comppareandswapint (this, valueOffset, e, u); }}Ini adalah bagian dari Kode Atomicboolean, dan kami melihat beberapa metode dan properti utama di sini.
1. Sun.misc.unsafe objek digunakan. Kelas ini menyediakan serangkaian metode untuk mengoperasikan objek memori secara langsung, tetapi hanya digunakan secara internal oleh JDK, dan tidak disarankan untuk digunakan pengembang;
2. Nilai mewakili nilai aktual. Anda dapat melihat bahwa metode GET sebenarnya menilai nilai boolean berdasarkan apakah nilainya sama dengan 0. Nilai di sini didefinisikan sebagai volatil, karena volatil dapat memastikan visibilitas memori, yaitu, selama nilai berubah, utas lain dapat melihat nilai yang diubah segera. Artikel berikutnya akan berbicara tentang visibilitas volatile, selamat datang untuk diikuti
3. ValueOffset adalah offset memori dari nilai nilai, diperoleh dengan menggunakan metode yang tidak aman.
4. Metode CompareANDSet, ini adalah metode inti untuk mengimplementasikan CA. Saat menggunakan metode Atomicboolean, Anda hanya perlu melewati nilai yang diharapkan dan nilai yang akan diperbarui. Metode yang tidak aman. Ini adalah metode asli, diimplementasikan dalam C ++, dan kode spesifik tidak akan diposting. Singkatnya, ia menggunakan instruksi CMMPXCHG CPU untuk menyelesaikan perbandingan dan penggantian. Tentu saja, tergantung pada versi sistem tertentu, ada juga perbedaan implementasi. Mereka yang tertarik dapat mencari artikel yang relevan sendiri.
Gunakan skenario
Misalnya, Atomicboolean dapat digunakan dalam skenario seperti itu. Sistem perlu menentukan apakah beberapa operasi inisialisasi perlu dilakukan berdasarkan sifat negara dari variabel boolean. Jika itu adalah lingkungan multi-threaded dan menghindari eksekusi berulang, itu dapat diimplementasikan menggunakan atomicboolean. Pseudocode adalah sebagai berikut:
flag atomicboolean statis final pribadi = atomicboolean baru (); if (flag.Compareandset (false, true)) {init (); }Misalnya, AtomicInteger dapat digunakan di counter dan di lingkungan multi-threaded untuk memastikan penghitungan yang akurat.
Pertanyaan aba
Ada masalah dengan CAS, yaitu bahwa nilai berubah dari A ke B dan kemudian dari B ke A. Dalam hal ini, CAS akan berpikir bahwa nilainya belum berubah, tetapi pada kenyataannya telah berubah. Dalam hal ini, ada atomicstampedreference di bawah paket bersamaan yang memberikan implementasi berdasarkan nomor versi, yang dapat menyelesaikan beberapa masalah.
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.