mvn deploy:deploy-file -DgroupId=org.csource.fastdfs -DartifactId=fastdfs-client -Dversion=1.24 -Dpackaging=jar -Dfile=D:\\fastdfs-client-1.24.jar -Durl=http://172.16.6.214:8081/nexus/content/groups/public/ -DrepositoryId=nexus
JAR創建到本地
少年阿賓那些青春的歲月 |
JAR上傳到NEXUS
mvn deploy:deploy-file -DgroupId=org.csource.fastdfs -DartifactId=fastdfs-client -Dversion=1.24 -Dpackaging=jar -Dfile=D:\\fastdfs-client-1.24.jar -Durl=http://172.16.6.214:8081/nexus/content/groups/public/ -DrepositoryId=nexus JAR創建到本地 mvn install:install-file -DgroupId=com.home.link -DartifactId=fastdfs-client -Dversion=1.24 -Dpackaging=jar -Dfile=D:\\fastdfs-client-1.24.jar RAID 是“獨立磁盤冗余陣列”(最初為“廉價磁盤冗余陣列”)的縮略語,1987 年由Patterson, Gibson 和Katz 在加州大學伯克利分院的一篇文章中定義。RAID 陣列技術允許將一系列磁盤分組,以實現提高可用性的目的,并提供為實現數據保護而必需的數據冗余,有時還有改善性能的作用。我們將對七個RAID 級別: 0,1,3,5,10,30 和50 作些說明。最前面的4 個級別0,1,3,5,)已被定為工業標準,10 級、30 級和50 級則反應了ACCSTOR2000 磁盤陣列可以提供的功能。了解每個級別的特征將有助于您判斷哪個級別最適合您的需要,本文的最后一部分將提供一份指導方針,幫助您選擇最適合您需要的RAID 級別。RAID 級別可以通過軟件或硬件實現。許多但不是全部網絡操作系統支持的RAID 級別至少要達到5 級,RAID10、30和50 在ACCSTOR2000 磁盤陣列控制下才能實現?;谲浖?span lang="EN-US">RAID 需要使用主機CPU 周期和系統內存,從而增加了系統開銷,直接影響系統的性能。磁盤陣列控制器把RAID 的計算和操縱工作由軟件移到了專門的硬件上,一般比軟件實現RAID 的系統性能要好。
JDK中的實現 在JDK中LinkedHashMap可以作為LRU算法以及插入順序的實現,LinkedHashMap繼承自HashMap,底層結合hash表和雙向鏈表,元素的插入和查詢等操作通過計算hash值找到其數組位置,在做插入或則查詢操作是,將元素插入到鏈表的表頭(當然得先刪除鏈表中的老元素),如果容量滿了,則刪除LRU這個元素,在鏈表表尾的元素即是。 LinkedHashMap的時間復雜度和HashMap差不多,雙向鏈表的刪除和表頭插入等操作都是O(1)復雜度,故不會影響HashMap的操作性能,插入,查詢,刪除LRU元素等操作均是O(1)的時間復雜度。 LinkedHashMap不是線程安全的類,用于多線程緩存則需要花點心思去同步它了,JDK中有支持并發的高性能ConcurrenHashMap,沒有ConcurrenListHashMap的實現,故要使用支持并發的高性能LRU算法還得靠自己去繼承ConcurrenHashMap或則其他方式實現。Google以及其它資深研發團隊已有ConcurrenListHashMap的實現 當然知道了原理,我們自己也可以來實現LRU算法 1.簡單的計數或則LU時間標記法 底層使用hash表,插入和訪問的時間都可以做到O(1)復雜度,容量滿了需要刪除LRU,則需要遍歷一遍數組,通過計數或則LU時間得到LRU,刪除之,時間復雜度O(n)。此算法簡單容易實現,適合數據量不大的需求 2.通過?;螂p向鏈表 這種算法通過維護元素的在鏈表中的順序來達到計算元素的訪問熱度,不需要額外的空間來計數或則記錄訪問時間。 插入時,先檢查改元素存在此鏈表中沒有,有的刪除之,然后再將元素插入表頭。 訪問時,遍歷數組查找該元素,然后將該元素移動至表頭。 這樣一來,最近被訪問的元素都在表頭,故要找出LRU則只需要刪除表尾元素即可。插入和訪問的時間復雜度均為O(n),如果用來作為緩存(查詢操作頻繁),相比hash表的實現,性能相當不好啊 3.結合HashMap和雙向鏈表 通過上面可知道HashMap可實現讀寫O(1)復雜度,但是找出LRU需要遍歷整個數組,而通過維護鏈表則相反,僅需要O(1)就可以找出LRU,故將兩者結合起來,實現綜合復雜度為O(1)的LRU算法 使用數組來存放元素,插入時通過hash計算出其位置,然后改變該元素在鏈表中的指針,兩個操作的時間復雜度均為1。具體實現可參考JDK的LinkedHashMap http://www.360doc.com/content/14/0402/09/10504424_365635496.shtml Zookeeper的核心是原子廣播,這個機制保證了各個Server之間的同步。實現這個機制的協議叫做Zab協議。Zab協議有兩種模式,它們分別是恢復模式(選主)和廣播模式(同步)。當服務啟動或者在領導者崩潰后,Zab就進入了恢復模式,當領導者被選舉出來,且大多數Server完成了和leader的狀態同步以后,恢復模式就結束了。狀態同步保證了leader和Server具有相同的系統狀態。 為了保證事務的順序一致性,zookeeper采用了遞增的事務id號(zxid)來標識事務。所有的提議(proposal)都在被提出的時候加上了zxid。實現中zxid是一個64位的數字,它高32位是epoch用來標識leader關系是否改變,每次一個leader被選出來,它都會有一個新的epoch,標識當前屬于那個leader的統治時期。低32位用于遞增計數。 每個Server在工作過程中有三種狀態: LOOKING:當前Server不知道leader是誰,正在搜尋 LEADING:當前Server即為選舉出來的leader FOLLOWING:leader已經選舉出來,當前Server與之同步 Leader選舉流程: 當leader崩潰或者leader失去大多數的follower,這時候zk進入恢復模式,恢復模式需要重新選舉出一個新的leader,讓所有的Server都恢復到一個正確的狀態。Zk的選舉算法有兩種:一種是基于basic paxos實現的,另外一種是基于fast paxos算法實現的。系統默認的選舉算法為fast paxos。先介紹basic paxos流程: 1 .選舉線程由當前Server發起選舉的線程擔任,其主要功能是對投票結果進行統計,并選出推薦的Server; 2 .選舉線程首先向所有Server發起一次詢問(包括自己); 3 .選舉線程收到回復后,驗證是否是自己發起的詢問(驗證zxid是否一致),然后獲取對方的id(myid),并存儲到當前詢問對象列表中,最后獲取對方提議的leader相關信息( id,zxid),并將這些信息存儲到當次選舉的投票記錄表中; 4. 收到所有Server回復以后,就計算出zxid最大的那個Server,并將這個Server相關信息設置成下一次要投票的Server; 5. 線程將當前zxid最大的Server設置為當前Server要推薦的Leader,如果此時獲勝的Server獲得n/2 + 1的Server票數, 設置當前推薦的leader為獲勝的Server,將根據獲勝的Server相關信息設置自己的狀態,否則,繼續這個過程,直到leader被選舉出來。 通過流程分析我們可以得出:要使Leader獲得多數Server的支持,則Server總數必須是奇數2n+1,且存活的Server的數目不得少于n+1. 每個Server啟動后都會重復以上流程。在恢復模式下,如果是剛從崩潰狀態恢復的或者剛啟動的server還會從磁盤快照中恢復數據和會話信息,zk會記錄事務日志并定期進行快照,方便在恢復時進行狀態恢復。 fast paxos流程是在選舉過程中,某Server首先向所有Server提議自己要成為leader,當其它Server收到提議以后,解決epoch和zxid的沖突,并接受對方的提議,然后向對方發送接受提議完成的消息,重復這個流程,最后一定能選舉出Leader。 zookeeper數據同步過程: 選完leader以后,zk就進入狀態同步過程。 1. leader等待server連接; 2 .Follower連接leader,將最大的zxid發送給leader; 3 .Leader根據follower的zxid確定同步點; 4 .完成同步后通知follower 已經成為uptodate狀態; 5 .Follower收到uptodate消息后,又可以重新接受client的請求進行服務了。 工作流程 Leader工作流程 Leader主要有三個功能: 1 .恢復數據; 2 .維持與Learner的心跳,接收Learner請求并判斷Learner的請求消息類型; 3 .Learner的消息類型主要有PING消息、REQUEST消息、ACK消息、REVALIDATE消息,根據不同的消息類型,進行不同的處理。 PING消息是指Learner的心跳信息;REQUEST消息是Follower發送的提議信息,包括寫請求及同步請求;ACK消息是Follower的對提議的回復,超過半數的Follower通過,則commit該提議;REVALIDATE消息是用來延長SESSION有效時間。Leader的工作流程簡圖如下所示,在實際實現中,流程要比下圖復雜得多,啟動了三個線程來實現功能。 2.3.2 Follower工作流程 Follower主要有四個功能: 1. 向Leader發送請求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息); 2 .接收Leader消息并進行處理; 3 .接收Client的請求,如果為寫請求,發送給Leader進行投票; 4 .返回Client結果。 Follower的消息循環處理如下幾種來自Leader的消息: 1 .PING消息:心跳消息; 2 .PROPOSAL消息:Leader發起的提案,要求Follower投票; 3 .COMMIT消息:服務器端最新一次提案的信息; 4 .UPTODATE消息:表明同步完成; 5 .REVALIDATE消息:根據Leader的REVALIDATE結果,關閉待revalidate的session還是允許其接受消息; 6 .SYNC消息:返回SYNC結果到客戶端,這個消息最初由客戶端發起,用來強制得到最新的更新。 Follower的工作流程簡圖如下所示,在實際實現中,Follower是通過5個線程來實現功能的。 http://www.it165.net/admin/html/201405/2997.html 靜態代理 靜態代理相對來說比較簡單,無非就是聚合+多態: 參考:設計模式筆記 – Proxy 代理模式 (Design Pattern) 動態代理 我們知道,通過使用代理,可以在被代理的類的方法的前后添加一些處理方法,這樣就達到了類似AOP的效果。而JDK中提供的動態代理,就是實現AOP的絕好底層技術。 JDK動態代理 JDK動態代理主要涉及到java.lang.reflect包中的兩個類:Proxy和InvocationHandler。InvocationHandler是一個接口,通過實現該接口定義橫切邏輯,并通過反射機制調用目標類的代碼,動態將橫切邏輯和業務邏輯編制在一起。 Proxy利用InvocationHandler動態創建一個符合某一接口的實例,生成目標類的代理對象。 例子:Java筆記 – 反射 動態代理 CGLib動態代理 還有一個叫CGLib的動態代理,CGLib全稱為Code Generation Library,是一個強大的高性能,高質量的代碼生成類庫,可以在運行期擴展Java類與實現Java接口,CGLib封裝了asm,可以再運行期動態生成新的class。和JDK動態代理相比較:JDK創建代理有一個限制,就是只能為接口創建代理實例,而對于沒有通過接口定義業務方法的類,則可以通過CGLib創建動態代理。 CGLib采用非常底層的字節碼技術,可以為一個類創建子類,并在子類中采用方法攔截的技術攔截所有父類方法的調用,并順勢織入橫切邏輯。 JDK動態代理和CGLib的比較 CGLib所創建的動態代理對象的性能比JDK所創建的代理對象性能高不少,大概10倍,但CGLib在創建代理對象時所花費的時間卻比JDK動態代理多大概8倍,所以對于singleton的代理對象或者具有實例池的代理,因為無需頻繁的創建新的實例,所以比較適合CGLib動態代理技術,反之則適用于JDK動態代理技術。另外,由于CGLib采用動態創建子類的方式生成代理對象,所以不能對目標類中的final,private等方法進行處理。所以,大家需要根據實際的情況選擇使用什么樣的代理了。 同樣的,Spring的AOP編程中相關的ProxyFactory代理工廠內部就是使用JDK動態代理或CGLib動態代理的,通過動態代理,將增強(advice)應用到目標類中。 JDK動態代理主要用到java.lang.reflect包中的兩個類:Proxy和InvocationHandler. InvocationHandler是一個接口,通過實現該接口定義橫切邏輯,并通過反射機制調用目標類的代碼,動態的將橫切邏輯和業務邏輯編織在一起。 Proxy利用InvocationHandler動態創建一個符合某一接口的實例,生成目標類的代理對象。 Cookie攻擊:
防止Cookie被抓包了之后攻擊: 就是驗證的東西盡量多就行了,比如里面添加IP驗證,添加一些MAC地址,添加有效期,添加 NIO通常采用Reactor模式,AIO通常采用Proactor模式。AIO簡化了程序的編寫,stream的讀取和寫入都有OS來完成,不需 要像NIO那樣子遍歷Selector。Windows基于IOCP實現AIO,Linux只有eppoll模擬實現了AIO。 基于原生nio的socket通信時一種很好的解決方案,基于事件的通知模式使得多并發時不用維持高數量的線程,高并發的socket服務器的java實現成為現實。不過原生nio代碼十分復雜,無論編寫還是修改都是一件頭疼的事。“屏蔽底層的繁瑣工作,讓程序員將注意力集中于業務邏輯本身”,有需求就有生產力進步, 狀態模式(state pattern)和策略模式(strategy pattern)的實現方法非常類似,都是利用多態把一些操作分配到一組相關的簡單的類中,因此很多人認為這兩種模式實際上是相同的。然而 •在現實世界中,策略(如促銷一種商品的策略)和狀態(如同一個按鈕來控制一個電梯的狀態,又如手機界面中一個按鈕來控制手機)是兩種完全不同的思想。當我們對狀態和策略進行建模時,這種差異會導致完全不同的問題。例如,對狀態進行建模時,狀態遷移是一個核心內容;然而,在選擇策略時,遷移與此毫無關系。另外,策略模式允許一個客戶選擇或提供一種策略,而這種思想在狀態模式中完全沒有。 •一個策略是一個計劃或方案,通過執行這個計劃或方案,我們可以在給定的輸入條件下達到一個特定的目標。策略是一組方案,他們可以相互替換;選擇一個策略,獲得策略的輸出。策略模式用于隨不同外部環境采取不同行為的場合。我們可以參考微軟企業庫底層Object Builder的創建對象的strategy實現方式。 •而狀態模式不同,對一個狀態特別重要的對象,通過狀態機來建模一個對象的狀態;狀態模式處理的核心問題是狀態的遷移,因為在對象存在很多狀態情況下,對各個business flow,各個狀態之間跳轉和遷移過程都是及其復雜的。例如一個工作流,審批一個文件,存在新建、提交、已修改、HR部門審批中、老板審批中、HR審批失敗、老板審批失敗等狀態,涉及多個角色交互,涉及很多事件,這種情況下用狀態模式(狀態機)來建模更加合適;把各個狀態和相應的實現步驟封裝成一組簡單的繼承自一個接口或抽象類的類,通過另外的一個Context來操作他們之間的自動狀態變換,通過event來自動實現各個狀態之間的跳轉。在整個生命周期中存在一個狀態的遷移曲線,這個遷移曲線對客戶是透明的。我們可以參考微軟最新的WWF 狀態機工作流實現思想。 •在狀態模式中,狀態的變遷是由對象的內部條件決定,外界只需關心其接口,不必關心其狀態對象的創建和轉化;而策略模式里,采取何種策略由外部條件(C)決定。
Spring什么時候實例化bean,首先要分2種情況
第一:如果你使用BeanFactory作為Spring Bean的工廠類,則所有的bean都是在第一次使用該Bean的時候實例化 第二:如果你使用ApplicationContext作為Spring Bean的工廠類,則又分為以下幾種情況: (1):如果bean的scope是singleton的,并且lazy-init為false(默認是false,所以可以不用設置),則ApplicationContext啟動的時候就實例化該Bean,并且將實例化的Bean放在一個map結構的緩存中,下次再使用該Bean的時候,直接從這個緩存中取 (2):如果bean的scope是singleton的,并且lazy-init為true,則該Bean的實例化是在第一次使用該Bean的時候進行實例化 (3):如果bean的scope是prototype的,則該Bean的實例化是在第一次使用該Bean的時候進行實例化 1、lazy init 在getBean時實例化 2、非lazy的單例bean 容器初始化時實例化 3、prototype等 getBean時實例化
<!--applicationContext.xml配置:--> <bean id="personService" class="cn.mytest.service.impl.PersonServiceBean"></bean> id是對象的名稱,class是要實例化的類,然后再通過正常的方式進調用實例化的類即可,比如: public void instanceSpring(){ //加載spring配置文件 ApplicationContext ac = new ClassPathXmlApplicationContext( new String[]{ "/conf/applicationContext.xml" }); //調用getBean方法取得被實例化的對象。 PersonServiceBean psb = (PersonServiceBean) ac.getBean("personService"); psb.save(); } 采用這種實例化方式要注意的是:要實例化的類中如果有構造器的話,一定要有一個無參的構造器。
二、使用靜態工廠方法實例化; 根據這個中實例化方法的名稱就可以知道要想通過這種方式進行實例化就要具備兩個條件:(一)、要有工廠類及其工廠方法;(二)、工廠方法是靜態的。OK,知道這兩點就好辦了,首先創建工程類及其靜態方法: package cn.mytest.service.impl; /** *創建工廠類 * */ public class PersonServiceFactory { //創建靜態方法 public static PersonServiceBean createPersonServiceBean(){ //返回實例化的類的對象 return new PersonServiceBean(); } } 然后再去配置spring配置文件,配置的方法和上面有點不同,這里也是關鍵所在<!--applicationContext.xml配置:--> <bean id="personService1" class="cn.mytest.service.impl.PersonServiceFactory" factory-method="createPersonServiceBean"></bean> id是實例化的對象的名稱,class是工廠類,也就實現實例化類的靜態方法所屬的類,factory-method是實現實例化類的靜態方法。 然后按照正常的調用方法去調用即可: public void instanceSpring(){ //加載spring配置文件 ApplicationContext ac = new ClassPathXmlApplicationContext( new String[]{ "/conf/applicationContext.xml" }); //調用getBean方法取得被實例化的對象。 PersonServiceBean psb = (PersonServiceBean) ac.getBean("personService1"); psb.save(); } 三、使用實例化工廠方法實例化。 這個方法和上面的方法不同之處在與使用該實例化方式工廠方法不需要是靜態的,但是在spring的配置文件中需要配置更多的內容,,首先創建工廠類及工廠方法: package cn.mytest.service.impl; /** *創建工廠類 * */ public class PersonServiceFactory { //創建靜態方法 public PersonServiceBean createPersonServiceBean1(){ //返回實例化的類的對象 return new PersonServiceBean(); } } 然后再去配置spring配置文件,配置的方法和上面有點不同,這里也是關鍵所在<!--applicationContext.xml配置:--> <bean id="personServiceFactory" class="cn.mytest.service.impl.PersonServiceFactory"></bean> <bean id="personService2" factory-bean="personServiceFactory" factory-method="createPersonServiceBean1"></bean> 這里需要配置兩個bean,第一個bean使用的構造器方法實例化工廠類,第二個bean中的id是實例化對象的名稱,factory-bean對應的被實例化的工廠類的對象名稱,也就是第一個bean的id,factory-method是非靜態工廠方法。
然后按照正常的調用方法去調用即可: public void instanceSpring(){ //加載spring配置文件 ApplicationContext ac = new ClassPathXmlApplicationContext( new String[]{ "/conf/applicationContext.xml" }); //調用getBean方法取得被實例化的對象。 PersonServiceBean psb = (PersonServiceBean) ac.getBean("personService2"); psb.save(); }
所謂原子操作,就是"不可中斷的一個或一系列操作" 。
硬件級的原子操作: 在單處理器系統(UniProcessor)中,能夠在單條指令中完成的操作都可以認為是" 原子操作",因為中斷只能發生于指令之間。這也是某些CPU指令系統中引入了test_and_set、test_and_clear等指令用于臨界資源互斥的原因。 在對稱多處理器(Symmetric Multi-Processor)結構中就不同了,由于系統中有多個處理器在獨立地運行,即使能在單條指令中完成的操作也有可能受到干擾。 在x86 平臺上,CPU提供了在指令執行期間對總線加鎖的手段。CPU芯片上有一條引線#HLOCK pin,如果匯編語言的程序中在一條指令前面加上前綴"LOCK",經過匯編以后的機器代碼就使CPU在執行這條指令的時候把#HLOCK pin的電位拉低,持續到這條指令結束時放開,從而把總線鎖住,這樣同一總線上別的CPU就暫時不能通過總線訪問內存了,保證了這條指令在多處理器環境中的 原子性。 軟件級的原子操作: 軟件級的原子操作實現依賴于硬件原子操作的支持。 對于linux而言,內核提供了兩組原子操作接口:一組是針對整數進行操作;另一組是針對單獨的位進行操作。 2.1. 原子整數操作 針對整數的原子操作只能對atomic_t類型的數據處理。這里沒有使用C語言的int類型,主要是因為: 1) 讓原子函數只接受atomic_t類型操作數,可以確保原子操作只與這種特殊類型數據一起使用 2) 使用atomic_t類型確保編譯器不對相應的值進行訪問優化 3) 使用atomic_t類型可以屏蔽不同體系結構上的數據類型的差異。盡管Linux支持的所有機器上的整型數據都是32位,但是使用atomic_t的代碼只能將該類型的數據當作24位來使用。這個限制完全是因為在SPARC體系結構上,原子操作的實現不同于其它體系結構:32位int類型的低8位嵌入了一個鎖,因為SPARC體系結構對原子操作缺乏指令級的支持,所以只能利用該鎖來避免對原子類型數據的并發訪問。 原子整數操作最常見的用途就是實現計數器。原子整數操作列表在中定義。原子操作通常是內斂函數,往往通過內嵌匯編指令來實現。如果某個函數本來就是原子的,那么它往往會被定義成一個宏。 在編寫內核時,操作也簡單: atomic_t use_cnt; atomic_set(&use_cnt, 2); atomic_add(4, &use_cnt); atomic_inc(use_cnt); 2.2. 原子性與順序性 原子性確保指令執行期間不被打斷,要么全部執行,要么根本不執行。而順序性確保即使兩條或多條指令出現在獨立的執行線程中,甚至獨立的處理器上,它們本該執行的順序依然要保持。 2.3. 原子位操作 原子位操作定義在文件中。令人感到奇怪的是位操作函數是對普通的內存地址進行操作的。原子位操作在多數情況下是對一個字長的內存訪問,因而位號該位于0-31之間(在64位機器上是0-63之間),但是對位號的范圍沒有限制。 編寫內核代碼,只要把指向了你希望的數據的指針給操作函數,就可以進行位操作了: unsigned long word = 0; set_bit(0, &word); /*第0位被設置*/ set_bit(1, &word); /*第1位被設置*/ clear_bit(1, &word); /*第1位被清空*/ change_bit(0, &word); /*翻轉第0位*/ 為什么關注原子操作? 1)在確認一個操作是原子的情況下,多線程環境里面,我們可以避免僅僅為保護這個操作在外圍加上性能開銷昂貴的鎖。 2)借助于原子操作,我們可以實現互斥鎖。 3)借助于互斥鎖,我們可以把一些列操作變為原子操作。 GNU C中x++是原子操作嗎? 答案不是。x++由3條指令完成。x++在單CPU下不是原子操作。 對應3條匯編指令 movl x, %eax addl $1, %eax movl %eax, x 在vc2005下對應 ++x; 004232FA mov eax,dword ptr [x] 004232FD add eax,1 00423300 mov dword ptr [x],eax 仍然是3條指令。 所以++x,x++等都不是原子操作。因其步驟包括了從內存中取x值放入寄存器,加寄存器,把值寫入內存三個指令。 如何實現x++的原子性? 在單處理器上,如果執行x++時,禁止多線程調度,就可以實現原子。因為單處理的多線程并發是偽并發。 在多處理器上,需要借助cpu提供的Lock功能。鎖總線。讀取內存值,修改,寫回內存三步期間禁止別的CPU訪問總線。同時我估計使用Lock指令鎖總線的時候,OS也不會把當前線程調度走了。要是調走了,那就麻煩了。 在多處理器系統中存在潛在問題的原因是: 不使用LOCK指令前綴鎖定總線的話,在一次內存訪問周期中有可能其他處理器會產生異?;蛑袛?,而在異常處理中有可能會修改尚未寫入的地址,這樣當INC操作完成后會產生無效數據(覆蓋了前面的修改)。 spinlock 用于CPU同步, 它的實現是基于CPU鎖定數據總線的指令. 當某個CPU鎖住數據總線后, 它讀一個內存單元(spinlock_t)來判斷這個spinlock 是否已經被別的CPU鎖住. 如果否, 它寫進一個特定值, 表示鎖定成功, 然后返回. 如果是, 它會重復以上操作直到成功, 或者spin次數超過一個設定值. 鎖定數據總線的指令只能保證一個機器指令內, CPU獨占數據總線. 單CPU當然能用spinlock, 但實現上無需鎖定數據總線. spinlock在鎖定的時候,如果不成功,不會睡眠,會持續的嘗試,單cpu的時候spinlock會讓其它process動不了. |