Apabila berbilang utas mengakses kelas, tanpa mengira kaedah panggilan yang digunakan oleh persekitaran masa jalan atau utas. pelaksanaan dilaksanakan secara bergilir-gilir, dan kelas ini boleh menunjukkan tingkah laku yang betul tanpa sebarang penyegerakan atau penyelarasan tambahan dalam kod panggilan utama, maka kelas ini dikatakan selamat untuk benang.
Objek tanpa status mestilah selamat untuk benang, seperti: Servlet
.
Keadaan perlumbaan berlaku apabila keputusan yang salah berlaku disebabkan oleh pemasaan pelaksanaan yang tidak betul.
Operasi "semak dahulu dan kemudian laksana" adalah untuk memutuskan tindakan seterusnya berdasarkan kemungkinan hasil pemerhatian praktikal. Contohnya: pemula malas.
if(instance == null) { instance = new SomeObject(); }
Operasi "Baca-ubah suai-tulis", keadaan hasil bergantung pada keadaan sebelumnya. Seperti: operasi kenaikan.
long count = 0; count++;
Kendalian atom bermaksud bahawa untuk semua operasi yang mengakses keadaan yang sama (termasuk operasi itu sendiri), operasi ini dilakukan dengan cara atom (tidak boleh dibahagikan).
Untuk memastikan keselamatan benang, satu set operasi yang mesti dilakukan secara atom disertakan, dipanggil operasi kompaun.
Operasi tambahan boleh menggunakan kelas selamat benang sedia ada untuk memastikan keselamatan benang. Contohnya:
AtomicLong count = new AtomicLong(0); count.incrementAndGet();
Jika kelas hanya mempunyai satu pembolehubah keadaan, anda boleh memastikan keselamatan urutan kelas dengan menggunakan pembolehubah keadaan selamat benang. Apabila kelas mempunyai lebih banyak keadaan, ia tidak mencukupi untuk hanya menambah lebih banyak pembolehubah keadaan selamat benang. Untuk memastikan ketekalan keadaan, semua pembolehubah keadaan yang berkaitan mesti dikemas kini dalam satu operasi atom.
Java menyediakan kunci terbina dalam: blok kod disegerakkan, yang merangkumi: rujukan objek sebagai kunci , objek sebagai Blok kod yang dilindungi oleh kunci ini.
Kaedah yang diubah suai dengan kata kunci synchronized
ialah blok kod penyegerakan yang merangkumi keseluruhan badan kaedah, di mana kunci blok kod penyegerakan ialah objek di mana panggilan kaedah berada. Kaedah synchronized
statik menggunakan objek Kelas sebagai kunci.
Apabila benang memasuki blok kod disegerakkan, kunci diperoleh secara automatik dan apabila benang keluar dari blok kod disegerakkan, kunci dilepaskan secara automatik. Paling banyak satu utas boleh memegang kunci ini, jadi kod penyegerakan dilaksanakan secara atom.
Kunci terbina dalam ialah masuk semula, yang bermaksud bahawa butiran operasi untuk memperoleh kunci ialah benang, bukan panggilan. Apabila benang cuba mendapatkan semula kunci yang telah dipegang olehnya, permintaan itu juga berjaya.
Reentrancy menambah baik pengkapsulan gelagat mengunci dan memudahkan pembangunan kod serentak berorientasikan objek.
public class Widget { public synchronized void doSomething() { //...... } } public class LoggingWidget extends Widget { public synchronized void doSomething() { //...... super.doSomething();//假如没有可重入的锁,该语句将产生死锁。 } }
Untuk pembolehubah keadaan boleh ubah yang boleh diakses oleh berbilang benang pada masa yang sama, anda perlu memegang kunci yang sama semasa mengaksesnya , dikatakan pembolehubah keadaan dilindungi oleh kunci ini.
Penggunaan kunci berbutir kasar memastikan keselamatan benang, tetapi boleh menyebabkan masalah prestasi dan keaktifan, seperti:
@ThreadSafe public class SynchronizedFactorizer implements Servlet { @GuardedBy("this") private BigInteger lastNumber; @GuardedBy("this") private BigInteger[] lastFactors; public synchronized void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); if (i.equals(lastNumber)) encodeIntoResponse(resp, lastFactors); else { BigInteger[] factors = factor(i);//因数分解计算 lastNumber = i; lastFactors = factors;//存放上一次计算结果 encodeIntoResponse(resp, factors); } } }
Anda boleh memastikan keselarasan servlet dan mengekalkan keselamatan benang dengan mengecilkan blok kod penyegerakan. Jangan bahagikan operasi atom kepada berbilang blok kod disegerakkan dan cuba pisahkan operasi yang tidak menjejaskan keadaan kongsi dan mengambil masa yang lama untuk dilaksanakan daripada kod disegerakkan. Seperti:
public class CachedFactorizer implements Servlet { @GuardedBy("this") private BigInteger lastNumber; @GuardedBy("this") private BigInteger[] lastFactors; public void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); BigInteger[] factors = null; synchronized (this) { if (i.equals(lastNumber)) { factors = lastFactors.clone(); } } if (factors == null) { factors = factor(i); synchronized (this) { lastNumber = i; lastFactors = factors.clone(); } } encodeIntoResponse(resp, factors); } }
Atas ialah kandungan terperinci Bagaimana untuk melaksanakan keselamatan benang dalam pengaturcaraan serentak Java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!