免費學(xué)習(xí)推薦:java基礎(chǔ)教程
Lock鎖與生產(chǎn)者消費者問題
- 傳統(tǒng)Synchronized鎖
- Lock鎖
- Synchronized和lock鎖的區(qū)別
- 傳統(tǒng)的生產(chǎn)者和消費者問題
- Lock版的生產(chǎn)者和消費者問題
- Condition實現(xiàn)精準(zhǔn)通知喚醒
傳統(tǒng)Synchronized鎖
實現(xiàn)一個基本的售票例子:
/* 真正的多線程開發(fā),公司中的開發(fā),降低耦合性 線程就是一個單獨的資源類,沒有任何附屬的操作 1.屬性,方法 ?*?*/public?class?SaleTicketDemo1?{ ????public?static?void?main(String[]?args)?{ ????????//并發(fā),多個線程操作同一個資源類,把資源類丟入線程 ????????Ticket?ticket=new?Ticket(); ????????//Runnable借口是一個FunationalInterface函數(shù)式接口,接口可以new,jdk1.8以后,lamda表達(dá)式()->{代碼} ????????new?Thread(()->{ ????????????for(int?i=0;i<60;i++){ ticket.sale(); } },"A").start(); new Thread(new Runnable() { @Override public void run() { for(int i=0;i<60;i++){ ticket.sale(); } } },"B").start(); new Thread(()->{ ????????????for(int?i=0;i<60;i++){ ticket.sale(); } },"C").start(); }}//資源類 OOPclass Ticket{ //屬性,方法 private int number=50; //賣票的方式 //synchronized本質(zhì):隊列,所 public synchronized void sale(){ if(number>0){ ????????????System.out.println(Thread.currentThread().getName()+"賣出了"+(number--)+"票,剩余"+number); ????????} ????}}
注意,這里面用到了lambda表達(dá)式,lambda表達(dá)式詳細(xì)描述見Java基礎(chǔ)-Lambda表達(dá)式
這是使用傳統(tǒng)的synchronized實現(xiàn)并發(fā),synchronized的本質(zhì)就是隊列,鎖。就好比食堂排隊。如果沒有排隊,就會很亂。只有給一個人服務(wù)完成了,另一個人才能接收到服務(wù)。
Lock鎖
之前已經(jīng)說道,JVM提供了synchronized關(guān)鍵字來實現(xiàn)對變量的同步訪問以及用wait和notify來實現(xiàn)線程間通信。在jdk1.5以后,JAVA提供了Lock類來實現(xiàn)和synchronized一樣的功能,并且還提供了Condition來顯示線程間通信。
Lock類是Java類來提供的功能,豐富的api使得Lock類的同步功能比synchronized的同步更強大。
在java.util. Concurrent包中,里面有3個接口,Condition,lock(標(biāo)準(zhǔn)鎖)。ReadWriteLock鎖(讀寫鎖)
Lock實現(xiàn)提供比使用synchronized方法和語句可以獲得的更廣泛的鎖定操作。 它們允許更靈活的結(jié)構(gòu)化,可能具有完全不同的屬性,并且可以支持多個相關(guān)聯(lián)的對象Condition。
Lock?l?=?...;?l.lock();?try?{?//?access?the?resource?protected?by?this?lock?}?finally?{?l.unlock();?}
lock()表示加鎖,unlock()表示解鎖
JDK官方文檔中解釋
所有已知實現(xiàn)類:
ReentrantLock可重入鎖
ReentrantReadWriteLock.ReadLock 讀鎖
ReentrantReadWriteLock.writeLock寫鎖
先說ReentrantLock實現(xiàn)類:
ReentrantLock底層源碼構(gòu)造函數(shù)
公平鎖:十分公平,可以先來后到。但是問題如果一個3s和一個3h的進(jìn)程到達(dá),3h先,那么3s等3h,實際上也不利。
非公平鎖:十分不公平,可以插隊(默認(rèn))
之后,我們會具體解釋。
怎么用,用之前加鎖,用之后解鎖
//lock鎖三部曲
//1.new ReentranLock();構(gòu)造
//2.Lock.lock();加鎖
//3.finally();解鎖
public?class?SaleTicketDemo2?{ public?static?void?main(String[]?args)?{ //并發(fā),多個線程操作同一個資源類,把資源類丟入線程 Ticket?ticket=new?Ticket(); //Runnable借口是一個FunationalInterface函數(shù)式接口,接口可以new,jdk1.8以后,lamda表達(dá)式()->{代碼} new?Thread(()->{for(int?i=0;i<60;i++)ticket.sale();},"A").start(); new Thread(()->{for(int?i=0;i<60;i++)ticket.sale();},"B").start(); new Thread(()->{for(int?i=0;i<60;i++)ticket.sale();},"C").start(); }}//資源類 OOP//lock鎖三部曲//1.new ReentranLock();//2.Lock.lock();加鎖//3.finally();解鎖class Ticket2{ //屬性,方法 private int number=50; //賣票的方式 //synchronized本質(zhì):隊列,所 Lock lock=new ReentrantLock(); public void sale(){ lock.lock(); try { //業(yè)務(wù)代碼 if(number>0){ System.out.println(Thread.currentThread().getName()+"賣出了"+(number--)+"票,剩余"+number); } }?catch?(Exception?e)?{ //?TODO:?handle?exception }finally{ lock.unlock(); } }}
Synchronized和lock鎖的區(qū)別
1.synchronized是內(nèi)置的java關(guān)鍵字,lock是一個Java類
2.synchronized無法判斷獲取鎖的狀態(tài),lock可以判斷是否獲取到了鎖
3.synchronized會自動釋放鎖(a–),lock必須要手動釋放鎖!如果不釋放鎖,會導(dǎo)致死鎖
4.Synchronized線程1(獲得鎖,阻塞),線程2(等待,傻傻的等)
lock.tryLock()嘗試獲取鎖,不一定會一直等待下去
5.Synchronized可重入鎖,不可以中斷的,非公平鎖。Lock,可重入鎖,可以判斷鎖,公平與非公平可以自己設(shè)置(可以自己設(shè)置)
6.synchronized適合少量的代碼同步問題,lock鎖適合鎖大量的同步代碼
synchornized鎖對象和同步代碼塊方法
傳統(tǒng)的生產(chǎn)者和消費者問題
傳統(tǒng)的生產(chǎn)者和消費者是基于Object類的wait、notify方法和synchronized關(guān)鍵字來實現(xiàn)的。
在面試的時候,手寫生產(chǎn)者消費者代碼是很常見的事情。
面試筆試經(jīng)典問題:
單例模式+排序算法+生產(chǎn)者消費者+死鎖
生產(chǎn)者消費者問題synchronized版
線程之間的通信問題:生產(chǎn)者和消費者問題 等待喚醒,通知喚醒
線程交替執(zhí)行 A B 操作同一個變量number=0
A num+1
B num-1
注意:加鎖的方法中,執(zhí)行的思路是判斷等待+業(yè)務(wù)+通知
package?testConcurrent;/* 線程之間的通信問題:生產(chǎn)者和消費者問題????等待喚醒,通知喚醒 線程交替執(zhí)行?A?B?操作同一個變量number=0 A?num+1 B?num-1 ?*?*/public?class?A?{ public?static?void?main(String[]?args)?{ Data?data?=new?Data(); new?Thread(()->{ for(int?i=0;i<10;i++){ try { data.increment(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } },"A").start(); new Thread(()->{ for(int?i=0;i<10;i++){ try { data.decrement(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } },"B").start(); }}//判斷等待+業(yè)務(wù)+通知class Data{ //數(shù)字。資源類 private int number=0; //+1。多線程的情況下一定要加鎖。 public synchronized void increment() throws InterruptedException{ //判斷是否需要等待,如果不需要,就需要干活進(jìn)行業(yè)務(wù)操作 if(number!=0){ //等于1的時候,需要等待,緩沖區(qū)只有1個空位置 //等待操作 this.wait(); } number++; //進(jìn)行業(yè)務(wù)操作 System.out.println(Thread.currentThread().getName()+"=>"+number); //通知其他線程,我+1完畢了 this.notify(); } //-1 public?synchronized?void?decrement()?throws?InterruptedException{ if(number==0){ //等待 this.wait(); } number--; System.out.println(Thread.currentThread().getName()+"=>"+number); //通知其他線程,我-1完畢了 this.notify(); }}
如圖,基本可以實現(xiàn)所要求的功能,但是這樣還會出現(xiàn)問題,如果此時我再加上了兩個線程,則
new?Thread(()->{ for(int?i=0;i<10;i++){ try { data.increment(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } },"C").start(); new Thread(()->{ for(int?i=0;i<10;i++){ try { data.decrement(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } },"D").start();
這里結(jié)果中出現(xiàn)了2,輸出結(jié)果出現(xiàn)了問題。為什么呢?
為什么if判斷會出現(xiàn)問題:
if判斷只判斷一次。因為if判斷了之后,就已經(jīng)進(jìn)入了代碼的等待那一行,這時,在wait下的線程可能有多個,甚至包括生產(chǎn)者和消費者。有可能某個生產(chǎn)者執(zhí)行完了之后,喚醒的是另一個生產(chǎn)者。
在我們的官方文檔中就給出了解釋
public final void wait(long timeout) throws InterruptedException
導(dǎo)致當(dāng)前線程等待,直到另一個線程調(diào)用此對象的notify()方法或notifyAll()方法,或指定的時間已過。
線程也可以喚醒,而不會被通知,中斷或超時,即所謂的虛假喚醒 。 雖然這在實踐中很少會發(fā)生,但應(yīng)用程序必須通過測試應(yīng)該使線程被喚醒的條件來防范,并且如果條件不滿足則繼續(xù)等待。 換句話說,等待應(yīng)該總是出現(xiàn)在循環(huán)中,就像這樣:
synchronized (obj) { while (<condition does not hold>) ?????????????obj.wait(timeout); ?????????...?//?Perform?action?appropriate?to?condition ?????}
注意點:防止虛假喚醒問題。
我們代碼中用的是if判斷,而應(yīng)該用while判斷
package?testConcurrent;/* 線程之間的通信問題:生產(chǎn)者和消費者問題????等待喚醒,通知喚醒 線程交替執(zhí)行?A?B?操作同一個變量number=0 A?num+1 B?num-1 ?*?*/public?class?A?{ ????public?static?void?main(String[]?args)?{ ????????Data?data?=new?Data(); ????????new?Thread(()->{ ????????????for(int?i=0;i<10;i++){ try { data.increment(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } },"A").start(); new Thread(()->{ ????????????for(int?i=0;i<10;i++){ try { data.decrement(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } },"B").start(); new Thread(()->{ ????????????for(int?i=0;i<10;i++){ try { data.increment(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } },"C").start(); new Thread(()->{ ????????????for(int?i=0;i<10;i++){ try { data.decrement(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } },"D").start(); }}//判斷等待+業(yè)務(wù)+通知class Data{ //數(shù)字。資源類 private int number=0; //+1 public synchronized void increment() throws InterruptedException{ //判斷是否需要等待,如果不需要,就需要干活進(jìn)行業(yè)務(wù)操作 while(number!=0){ //等于1的時候,需要等待,緩沖區(qū)只有1個空位置 //等待操作 this.wait(); } number++; //進(jìn)行業(yè)務(wù)操作 System.out.println(Thread.currentThread().getName()+"=>"+number); ????????//通知其他線程,我+1完畢了 ????????this.notify(); ????} ????//-1 ????public?synchronized?void?decrement()?throws?InterruptedException{ ????????while(number==0){ ????????????//等待 ????????????this.wait(); ????????} ????????number--; ????????System.out.println(Thread.currentThread().getName()+"=>"+number); ????????//通知其他線程,我-1完畢了 ????????this.notify(); ????}}
Lock版的生產(chǎn)者和消費者問題
在synchronized版本中,我們使用了wait和notify來實現(xiàn)線程之間的同步
在lock中,
此時synchronized被lock替換了,那么wait和notify用什么來替換呢?
我們在官方文檔java.util.concurrent.locks 中,找到Lock類,然后在底部找到了
Condition newCondition()
返回一個新Condition綁定到該實例Lock實例。
在等待條件之前,鎖必須由當(dāng)前線程保持。 呼叫Condition.await()將在等待之前將原子釋放鎖,并在等待返回之前重新獲取鎖。
然后我們再來了解Condition類
Condition 將 Object 監(jiān)視器方法(wait、notify 和 notifyAll)分解成截然不同的對象,以便通過將這些對象與任意 Lock 實現(xiàn)組合使用,為每個對象提供多個等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和語句的使用,Condition 替代了 Object 監(jiān)視器方法的使用。
一個Condition實例本質(zhì)上綁定到一個鎖。 要獲得特定Condition實例的Condition實例,請使用其newCondition()方法。
我們可以看到,使用的時候new一個Condition對象。然后用await替代wait,signal替換notify
代碼實現(xiàn)
//判斷等待+業(yè)務(wù)+通知
class?Data2{ //數(shù)字。資源類 private?int?number=0; Lock?lock=new?ReentrantLock(); Condition?condition=lock.newCondition(); //+1 public?void?increment()?throws?InterruptedException{ try?{ lock.lock(); //業(yè)務(wù)代碼 while(number!=0){ //等待 condition.await(); } number++; System.out.println(Thread.currentThread().getName()+"=>"+number); condition.signalAll(); //通知 }?catch?(Exception?e)?{ //?TODO:?handle?exception }finally{ lock.unlock(); } } //-1 public?void?decrement()?throws?InterruptedException{ try?{ lock.lock(); //業(yè)務(wù)代碼 while(number!=1){ //等待 condition.await(); } number--; System.out.println(Thread.currentThread().getName()+"=>"+number); condition.signalAll(); //通知 }?catch?(Exception?e)?{ //?TODO:?handle?exception }finally{ lock.unlock(); } } }
注意:主函數(shù)部分于最上面的代碼一樣。
這時候雖然說是正確的,但是它是一個隨機(jī)分布的狀態(tài),現(xiàn)在我們希望它有序執(zhí)行,即A執(zhí)行完了執(zhí)行B,B執(zhí)行C,C完了執(zhí)行D。即精準(zhǔn)通知。
Condition實現(xiàn)精準(zhǔn)通知喚醒
Condition實現(xiàn)精準(zhǔn)的通知和喚醒
我們構(gòu)造三個線程,要求A執(zhí)行完了執(zhí)行B,B執(zhí)行完了執(zhí)行C,C執(zhí)行完了執(zhí)行D.
代碼思想:
//加多個監(jiān)視器,通過監(jiān)視器來判斷喚醒的是哪一個人
//設(shè)置多個同步監(jiān)視器,每個監(jiān)視器監(jiān)視一個線程
//實例:生產(chǎn)線,下單->支付->交易->物流
package?testConcurrent;import?java.util.concurrent.locks.Condition;import?java.util.concurrent.locks.Lock;import?java.util.concurrent.locks.ReentrantLock;/* A執(zhí)行完調(diào)用B,B執(zhí)行完調(diào)用C,C執(zhí)行完調(diào)用A ?*?*/public?class?C?{ ????public?static?void?main(String[]?args)?{ ????????Data3?data=new?Data3(); ????????new?Thread(()->{ ????????????for(int?i=0;i<10;i++){ data.printA(); } },"A").start(); new Thread(()->{ ????????????for(int?i=0;i<10;i++){ data.printB(); } },"B").start(); new Thread(()->{ ????????????for(int?i=0;i<10;i++){ data.printC(); } },"C").start(); }}class Data3{ //資源類 private Lock lock=new ReentrantLock(); //加多個監(jiān)視器,通過監(jiān)視器來判斷喚醒的是哪一個人 //設(shè)置多個同步監(jiān)視器,每個監(jiān)視器監(jiān)視一個線程 //實例:生產(chǎn)線,下單->支付->交易->物流 ????private?Condition?condition1=lock.newCondition(); ????private?Condition?condition2=lock.newCondition(); ????private?Condition?condition3=lock.newCondition(); ????private?int?number=1;???????//1A?2B?3C ????public?void?printA(){ ????????lock.lock(); ????????try?{ ????????????//業(yè)務(wù),判斷->執(zhí)行->通知 ????????????while(number!=1){ ????????????????//等待 ????????????????condition1.await(); ????????????} ????????????System.out.println(Thread.currentThread().getName()+"=>AAAAAAA"); ????????????//喚醒,喚醒指定的人,B ????????????number=2;???????????//精準(zhǔn)喚醒 ????????????condition2.signal(); ???????????? ????????}?catch?(Exception?e)?{ ????????????//?TODO:?handle?exception ????????}finally{ ????????????lock.unlock(); ????????} ????}??? ????public?void?printB(){ ????????lock.lock(); ????????try?{ ????????????//業(yè)務(wù),判斷->執(zhí)行->通知 ????????????while(number!=2){ ????????????????//等待 ????????????????condition2.await(); ????????????} ????????????System.out.println(Thread.currentThread().getName()+"=>BBBBBBB"); ????????????//喚醒,喚醒指定的人,C ????????????number=3;???????????//精準(zhǔn)喚醒 ????????????condition3.signal(); ???????????? ????????}?catch?(Exception?e)?{ ????????????//?TODO:?handle?exception ????????}finally{ ????????????lock.unlock(); ????????} ????} ????public?void?printC(){ ????????lock.lock(); ????????try?{ ????????????//業(yè)務(wù),判斷->執(zhí)行->通知 ????????????while(number!=3){ ????????????????//等待 ????????????????condition3.await(); ????????????} ????????????System.out.println(Thread.currentThread().getName()+"=>CCCCCCC"); ????????????//喚醒,喚醒指定的人,A ????????????number=1;???????????//精準(zhǔn)喚醒 ????????????condition1.signal(); ???????????? ????????}?catch?(Exception?e)?{ ????????????//?TODO:?handle?exception ????????}finally{ ????????????lock.unlock(); ????????} ????}}
相關(guān)學(xué)習(xí)推薦:java基礎(chǔ)
Atas ialah kandungan terperinci Java介紹Lock鎖與生產(chǎn)者消費者問題. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undress AI Tool
Gambar buka pakaian secara percuma

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Untuk mengendalikan transaksi JDBC dengan betul, anda mesti terlebih dahulu mematikan mod komit automatik, kemudian melakukan pelbagai operasi, dan akhirnya melakukan atau mengembalikan semula hasilnya; 1. Panggil Conn.SetAutOcommit (palsu) untuk memulakan transaksi; 2. Melaksanakan pelbagai operasi SQL, seperti memasukkan dan mengemaskini; 3. Panggil Conn.Commit () jika semua operasi berjaya, dan hubungi conn.rollback () jika pengecualian berlaku untuk memastikan konsistensi data; Pada masa yang sama, cuba-dengan-sumber harus digunakan untuk menguruskan sumber, mengendalikan pengecualian dengan betul dan menutup sambungan untuk mengelakkan kebocoran sambungan; Di samping itu, adalah disyorkan untuk menggunakan kolam sambungan dan menetapkan mata simpan untuk mencapai rollback separa, dan menyimpan urus niaga sesingkat mungkin untuk meningkatkan prestasi.

Gunakan kelas dalam pakej Java.Time untuk menggantikan kelas lama dan kelas kalendar; 2. Dapatkan tarikh dan masa semasa melalui LocalDate, LocalDateTime dan Tempatan Tempatan; 3. Buat tarikh dan masa tertentu menggunakan kaedah (); 4. Gunakan kaedah tambah/tolak untuk meningkatkan dan mengurangkan masa; 5. Gunakan zoneddatetime dan zonid untuk memproses zon waktu; 6. Format dan parse date string melalui DateTimeFormatter; 7. Gunakan segera untuk bersesuaian dengan jenis tarikh lama apabila perlu; pemprosesan tarikh di java moden harus memberi keutamaan untuk menggunakan java.timeapi, yang memberikan jelas, tidak berubah dan linear

Pra-formancetartuptimemoryusage, quarkusandmicronautleadduetocompile-timeprocessingandgraalvsupport, withquarkusoftenperforminglightbetterine serverless scenarios.tyvelopecosyste,

HTTP Log Middleware di GO boleh merakam kaedah permintaan, laluan, IP klien dan memakan masa. 1. Gunakan http.handlerfunc untuk membungkus pemproses, 2. Rekod waktu mula dan masa akhir sebelum dan selepas memanggil next.servehttp, 3. Dapatkan IP pelanggan sebenar melalui r.remoteaddr dan X-forward-for headers, 4. Gunakan log.printf untuk mengeluarkan log permintaan, 5. Kod sampel lengkap telah disahkan untuk dijalankan dan sesuai untuk memulakan projek kecil dan sederhana. Cadangan lanjutan termasuk menangkap kod status, menyokong log JSON dan meminta penjejakan ID.

Koleksi Sampah Java (GC) adalah mekanisme yang secara automatik menguruskan ingatan, yang mengurangkan risiko kebocoran ingatan dengan menuntut semula objek yang tidak dapat dicapai. 1.GC menghakimi kebolehcapaian objek dari objek akar (seperti pembolehubah stack, benang aktif, medan statik, dan lain -lain), dan objek yang tidak dapat dicapai ditandakan sebagai sampah. 2. Berdasarkan algoritma penandaan tanda, tandakan semua objek yang dapat dicapai dan objek yang tidak ditandai. 3. Mengamalkan strategi pengumpulan generasi: Generasi Baru (Eden, S0, S1) sering melaksanakan MinorGC; Orang tua melakukan kurang tetapi mengambil masa lebih lama untuk melakukan MajorGC; Metaspace Stores Metadata kelas. 4. JVM menyediakan pelbagai peranti GC: SerialGC sesuai untuk aplikasi kecil; ParallelGC meningkatkan throughput; CMS mengurangkan

Memilih jenis htmlinput yang betul dapat meningkatkan ketepatan data, meningkatkan pengalaman pengguna, dan meningkatkan kebolehgunaan. 1. Pilih jenis input yang sepadan mengikut jenis data, seperti teks, e -mel, tel, nombor dan tarikh, yang secara automatik boleh menyemak dan menyesuaikan diri dengan papan kekunci; 2. Gunakan HTML5 untuk menambah jenis baru seperti URL, Warna, Julat dan Carian, yang dapat memberikan kaedah interaksi yang lebih intuitif; 3. Gunakan pemegang tempat dan sifat -sifat yang diperlukan untuk meningkatkan kecekapan dan ketepatan pengisian bentuk, tetapi harus diperhatikan bahawa pemegang tempat tidak dapat menggantikan label.

GradleisthebetterChoiceFormostNewProjectSduetoitSsuperiorflexibility, Prestasi, danModernToolingSupport.1.Gradle'sGroovy/KOT lindslismoreconciseandexpressivethanmaven'sverbosexml.2.GradleOutPerformsMaveninBuildSpeedWithIncrementalcompilation, BuildCac

Defer digunakan untuk melaksanakan operasi tertentu sebelum fungsi pulangan, seperti sumber pembersihan; Parameter dinilai dengan serta-merta apabila menangguhkan, dan fungsi-fungsi dilaksanakan mengikut urutan terakhir (LIFO); 1. Pelbagai penahanan dilaksanakan dalam urutan terbalik pengisytiharan; 2. Biasanya digunakan untuk pembersihan yang selamat seperti penutupan fail; 3. Nilai pulangan yang dinamakan boleh diubah suai; 4. Ia akan dilaksanakan walaupun panik berlaku, sesuai untuk pemulihan; 5. Elakkan penyalahgunaan menangguhkan gelung untuk mengelakkan kebocoran sumber; Penggunaan yang betul boleh meningkatkan keselamatan kod dan kebolehbacaan.
