Rumah  >  Artikel  >  Java  >  Cara menggunakan penguncian optimistik CAS dan java

Cara menggunakan penguncian optimistik CAS dan java

王林
王林ke hadapan
2023-05-01 20:07:161090semak imbas

Apakah itu CAS

CAS ialah CompareAndSwap, yang bermaksud perbandingan dan pertukaran. Mengapakah CAS tidak menggunakan kunci tetapi masih memastikan manipulasi data yang selamat di bawah keadaan serentak Nama sebenarnya menunjukkan prinsip CAS dengan sangat intuitif Proses khusus mengubah suai data adalah seperti berikut:

  1. Gunakan. CAS untuk beroperasi Apabila data dijana, hantar nilai asal data dan nilai yang akan diubah suai kepada kaedah

  2. untuk membandingkan sama ada nilai pembolehubah sasaran semasa adalah sama dengan yang asal nilai yang diluluskan dalam

  3. Jika sama, bermakna pembolehubah sasaran belum diubah suai oleh utas lain, cuma ubah suai nilai pembolehubah sasaran secara terus

  4. Jika nilai pembolehubah sasaran berbeza daripada nilai asal, maka ia membuktikan pembolehubah sasaran telah diubah suai Benang lain telah diubah suai, dan pengubahsuaian CAS ini gagal

Daripada proses di atas , kita dapat melihat bahawa CAS sebenarnya menjamin pengubahsuaian data yang selamat, tetapi terdapat kemungkinan kegagalan dalam pengubahsuaian, iaitu, data pembolehubah sasaran Jika pengubahsuaian tidak berjaya, pada masa ini kita perlu gelung untuk menentukan keputusan CAS mengubah suai data, dan cuba lagi jika ia gagal.

Pelajar yang berfikir dengan lebih teliti mungkin bimbang bahawa operasi perbandingan dan penggantian CAS itu sendiri akan menyebabkan isu keselamatan serentak Dalam aplikasi sebenar, keadaan ini tidak akan berlaku oleh JDK dengan bantuan simpulan bahasa CAS peringkat perkakasan untuk memastikan bahawa perbandingan dan penggantian adalah tindakan atom.

CAS melaksanakan pengaturcaraan tanpa kunci

Pengaturcaraan bebas kunci merujuk kepada operasi selamat pembolehubah dikongsi tanpa menggunakan kunciDalam pengaturcaraan serentak, Kami menggunakan pelbagai kunci untuk memastikan keselamatan pembolehubah yang dikongsi. Iaitu, ia dijamin bahawa utas lain tidak boleh mengendalikan pembolehubah kongsi yang sama apabila satu utas belum selesai mengendalikan pembolehubah kongsi.
Penggunaan kunci yang betul boleh memastikan keselamatan data di bawah keselarasan, tetapi apabila tahap keselarasan tidak tinggi dan persaingan tidak sengit, memperoleh dan melepaskan kunci menjadi pembaziran prestasi yang tidak perlu. Dalam kes ini, anda boleh mempertimbangkan untuk menggunakan CAS untuk memastikan keselamatan data dan mencapai pengaturcaraan tanpa kunci

Masalah ABA yang menyusahkan

Kami telah pun memahami prinsip CAS untuk memastikan operasi yang selamat bagi pembolehubah dikongsi, tetapi CAS di atas Operasi ini juga cacat. Andaikan bahawa nilai pembolehubah kongsi yang diakses oleh utas semasa ialah A. Semasa proses utas 1 mengakses pembolehubah kongsi, utas 2 mengendalikan pembolehubah kongsi dan memberikannya nilai B. Selepas utas 2 memproses logiknya sendiri, ia memberikan pembolehubah kongsi nilai A. Pada masa ini, utas 1 membandingkan nilai pembolehubah kongsi A dengan nilai asal A, tersalah percaya bahawa tiada utas lain mengendalikan pembolehubah dikongsi dan secara langsung mengembalikan kejayaan operasi. Ini adalah masalah ABA. Walaupun kebanyakan perniagaan tidak perlu mengambil berat tentang sama ada terdapat perubahan lain pada pembolehubah yang dikongsi, selagi nilai asal konsisten dengan nilai semasa, hasil yang betul boleh diperolehi Walau bagaimanapun, terdapat beberapa senario sensitif di mana bukan sahaja hasil pembolehubah yang dikongsi bersamaan dengan tidak diubah suai, tetapi juga Ia tidak boleh diterima untuk pembolehubah yang dikongsi diubah suai oleh utas lain dalam proses. Nasib baik, terdapat penyelesaian matang untuk masalah ABA Kami menambah nombor versi pada pembolehubah kongsi, dan nilai nombor versi akan meningkat secara automatik setiap kali pembolehubah kongsi diubah suai. Dalam operasi CAS, yang kami bandingkan bukanlah nilai pembolehubah asal, tetapi nombor versi pembolehubah yang dikongsi. Nombor versi yang dikemas kini untuk setiap operasi pembolehubah yang dikongsi adalah unik, jadi masalah ABA boleh dielakkan.

Senario aplikasi khusus

Aplikasi CAS dalam JDK

Pertama sekali, adalah tidak selamat untuk berbilang rangkaian untuk melakukan operasi serentak pada pembolehubah biasa digunakan oleh utas lain, sebagai contoh, sekarang kita menggunakan dua utas, setiap utas meningkatkan pembolehubah yang dikongsi dengan nilai awal 1 per satu. Jika tiada mekanisme penyegerakan, hasil pembolehubah yang dikongsi mungkin kurang daripada 3. Iaitu, ada kemungkinan bahawa kedua-dua utas 1 dan utas 2 telah membaca nilai awal 1, utas 1 memberikannya kepada 2, dan nilai yang dibaca oleh utas 2 dari memori di mana ia berada tetap tidak berubah dengan 1 dan menetapkannya kepada 2, jadi Hasil akhir ialah 2 yang kurang daripada hasil jangkaan 3. Operasi kenaikan bukan operasi atom, yang membawa kepada masalah operasi pembolehubah kongsi yang tidak selamat. Untuk menyelesaikan masalah ini, JDK menyediakan satu siri kelas atom untuk menyediakan operasi atom yang sepadan. Berikut ialah kod sumber kaedah getAndIncrement dalam AtomicInteger Mari kita lihat kod sumber untuk melihat cara menggunakan CAS untuk melaksanakan penambahan atom selamat bagi pembolehubah integer.

rreeee

Anda boleh melihat bahawa getAndIncrement sebenarnya memanggil kaedah getAndAddInt kelas UnSafe untuk melaksanakan operasi atom Berikut ialah kod sumber getAndAddInt

<code>/**<br> * 原子性的将当前值增加1<br> *<br> * @return 返回自增前的值<br> */<br>public final int getAndIncrement() {<br>    return unsafe.getAndAddInt(this, valueOffset, 1);<br>}<br></code>

Kita semua biasa dengan kunci, seperti kunci reentrant ReentrantLock Pelbagai kunci yang disediakan oleh JDK pada asasnya bergantung pada kelas AbstractQueuedSynchronizer Apabila beberapa utas cuba memperoleh kunci, mereka akan memasuki baris gilir dan menunggu, termasuk berbilang -operasi enqueue thread. Keatomisan dijamin oleh CAS Kod sumber adalah seperti berikut:

<code>/**<br> * 原子的将给定值与目标字变量相加并重新赋值给目标变量<br> *<br> * @param o 要更新的变量所在的对象<br> * @param offset 变量字段的内存偏移值<br> * @param delta 要增加的数字值<br> * @return 更改前的原始值<br> * @since 1.8<br> */<br>public final int getAndAddInt(Object o, long offset, int delta) {<br>    int v;<br>    do {<br>    	// 获取当前目标目标变量值<br>        v = getIntVolatile(o, offset);<br>    // 这句代码是关键, 自旋保证相加操作一定成功<br>    // 如果不成功继续运行上一句代码, 获取被其他<br>    // 线程抢先修改的变量值, 在新值基础上尝试相加<br>    // 操作, 保证了相加操作的原子性<br>    } while (!compareAndSwapInt(o, offset, v, v + delta));<br>    return v;<br>}<br></code>

Aplikasi kunci yang optimistik dalam pembangunan perusahaan

Selain daripada pelbagai operasi atom yang disediakan oleh kelas Uusafe. dalam JDK, kami sebenarnya Semasa pembangunan, idea CAS boleh digunakan untuk memastikan operasi pangkalan data yang selamat di bawah keadaan serentak. Anggap bahawa struktur jadual dan data pengguna adalah seperti berikut Medan versi adalah kunci untuk melaksanakan penguncian optimistik

id user coupon_num version
1 朱小明 0 0
.

假设我们有一个用户领取优惠券的按钮,怎么防止用户快速点击按钮造成重复领取优惠券的情况呢。我们要安全的更改id为1的用户的coupon_num优惠券数量,将version字段作为CAS比较的版本号,即可避免重复增加优惠券数量,比较和替换这个逻辑通过WHERE条件来实现. 涉及sql如下:

<code>UPDATE user <br>SET coupon_num = coupon_num + 1, version = version + 1 <br>WHERE version = 0</code>

可以看到,我们查询出id为1的数据, 版本号为0,修改数据的同时把当前版本号当做条件即可实现安全修改,如果修改失败,证明已经被其他线程修改过,然后看具体业务决定是否需要自旋尝试再次修改。这里要注意考虑竞争激烈的情况下多个线程自旋导致过度的性能消耗,根据并发量选择适合自己业务的方式

Atas ialah kandungan terperinci Cara menggunakan penguncian optimistik CAS dan java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam