Java基礎——synchronized

synchronized


重要!重要!重要!重要的事情說三遍,一定要記下來哦。

Java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。

? ? ? ?一、當兩個并發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊。

? ? ? ?二、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。

? ? ? ?三、尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。

? ? ? ?四、第三個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。

? ? ? ?五、以上規則對其它對象鎖同樣適用。


舉例說明:

一、當兩個并發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊。

public class Thread1 implements Runnable {  public void run() {  synchronized(this) {  for (int i = 0; i < 5; i++) {  System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);  }  }  }  
}public class Main {public static void main(String[] args) {  Thread1 t1 = new Thread1();  Thread ta = new Thread(t1, "A");  Thread tb = new Thread(t1, "B");  ta.start();  tb.start();  } 
}
運行結果:
A synchronized loop 0  
A synchronized loop 1  
A synchronized loop 2  
A synchronized loop 3  
A synchronized loop 4  
B synchronized loop 0  
B synchronized loop 1  
B synchronized loop 2  
B synchronized loop 3  
B synchronized loop 4
二、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。
public class Thread2 {  public void m4t1() {  synchronized(this) {  int i = 5;  while( i-- > 0) {  System.out.println(Thread.currentThread().getName() + " : " + i);  try {  Thread.sleep(500);  } catch (InterruptedException ie) {  }  }  }  }  public void m4t2() {  int i = 5;  while( i-- > 0) {  System.out.println(Thread.currentThread().getName() + " : " + i);  try {  Thread.sleep(500);  } catch (InterruptedException ie) {  }  }  }  }public class Main {public static void main(String[] args) {  final Thread2 myt2 = new Thread2();  Thread t1 = new Thread(new Runnable() {  public void run() { myt2.m4t1(); } }, "t1");  Thread t2 = new Thread(new Runnable() {  public void run() { myt2.m4t2(); } }, "t2");  t1.start();  t2.start();  } 
}
運行結果:
t1 : 4  
t2 : 4  
t1 : 3  
t2 : 3  
t1 : 2  
t2 : 2  
t1 : 1  
t2 : 1  
t1 : 0  
t2 : 0

三、尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。

修改Thread2.m4t2()方法:

     public void m4t2() {  synchronized(this) {  int i = 5;  while( i-- > 0) {  System.out.println(Thread.currentThread().getName() + " : " + i);  try {  Thread.sleep(500);  } catch (InterruptedException ie) {  }  }  }}
運行結果:
t1 : 4  
t1 : 3  
t1 : 2  
t1 : 1  
t1 : 0  
t2 : 4  
t2 : 3  
t2 : 2  
t2 : 1  
t2 : 0

四、第三個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。

修改Thread2.m4t2()方法如下:

     public synchronized void m4t2() {  int i = 5;  while( i-- > 0) {  System.out.println(Thread.currentThread().getName() + " : " + i);  try {  Thread.sleep(500);  } catch (InterruptedException ie) {  }  }  }
五、以上規則對其它對象鎖同樣適用
public class Thread3 { class Inner { private void m4t1() { int i = 5; while(i-- > 0) { System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i); try { Thread.sleep(500); } catch(InterruptedException ie) { } } } private void m4t2() { int i = 5; while(i-- > 0) { System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i); try { Thread.sleep(500); } catch(InterruptedException ie) { } } } } private void m4t1(Inner inner) { synchronized(inner) { //使用對象鎖 inner.m4t1(); } private void m4t2(Inner inner) { inner.m4t2(); } }public class Main {public static void main(String[] args) { final Thread3 myt3 = new Thread3(); final Inner inner = myt3.new Inner(); Thread t1 = new Thread( new Runnable() {public void run() { myt3.m4t1(inner);} }, "t1"); Thread t2 = new Thread( new Runnable() {public void run() { myt3.m4t2(inner);} }, "t2"); t1.start(); t2.start(); }
}

運行結果:

t1 : Inner.m4t1()=4  
t2 : Inner.m4t2()=4  
t1 : Inner.m4t1()=3  
t2 : Inner.m4t2()=3  
t1 : Inner.m4t1()=2  
t2 : Inner.m4t2()=2  
t1 : Inner.m4t1()=1  
t2 : Inner.m4t2()=1  
t1 : Inner.m4t1()=0  
t2 : Inner.m4t2()=0
盡管線程t1獲得了對Inner的對象鎖,但由于線程t2訪問的是同一個Inner中的非同步部分。所以兩個線程互不干擾。

現在在Inner.m4t2()前面加上synchronized:
     private synchronized void m4t2() {  int i = 5;  while(i-- > 0) {  System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);  try {  Thread.sleep(500);  } catch(InterruptedException ie) {  }  }  }

運行結果:

t1 : Inner.m4t1()=4  
t1 : Inner.m4t1()=3  
t1 : Inner.m4t1()=2  
t1 : Inner.m4t1()=1  
t1 : Inner.m4t1()=0  
t2 : Inner.m4t2()=4  
t2 : Inner.m4t2()=3  
t2 : Inner.m4t2()=2  
t2 : Inner.m4t2()=1  
t2 : Inner.m4t2()=0
盡管線程t1與t2訪問了同一個Inner對象中兩個毫不相關的部分,但因為t1先獲得了對Inner的對象鎖,所以t2對Inner.m4t2()的訪問也被阻塞,因為m4t2()是Inner中的一個同步方法。

第二篇


synchronized 關鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。 ?

1. synchronized 方法:通過在方法聲明中加入 synchronized關鍵字來聲明 synchronized 方法。

如:??

public synchronized void accessVal(int newVal); 

? ? ? ?synchronized 方法控制對類成員變量的訪問:每個類實例對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的類實例的鎖方能執行,否則所屬線程阻塞,方法一旦執行,就獨占該鎖,直到從該方法返回時才將鎖釋放,此后被阻塞的線程方能獲得該鎖,重新進入可執行狀態。這種機制確保了同一時刻對于每一個類實例,其所有聲明為 synchronized 的成員函數中至多只有一個處于可執行狀態(因為至多只有一個能夠獲得該類實例對應的鎖),從而有效避免了類成員變量的訪問沖突(只要所有可能訪問類成員變量的方法均被聲明為 synchronized)。 ?

? ? ? ?在 Java 中,不光是類實例,每一個類也對應一把鎖,這樣我們也可將類的靜態成員函數聲明為 synchronized ,以控制其對類的靜態成員變量的訪問。 ?

synchronized 方法的缺陷:

? ? ? ?若將一個大的方法聲明為synchronized 將會大大影響效率,典型地,若將線程類的方法 run() 聲明為synchronized ,由于在線程的整個生命期內它一直在運行,因此將導致它對本類任何 synchronized 方法的調用都永遠不會成功。當然我們可以通過將訪問類成員變量的代碼放到專門的方法中,將其聲明為 synchronized ,并在主方法中調用來解決這一問題,但是 Java 為我們提供了更好的解決辦法,那就是 synchronized 塊。 ?

2. synchronized 塊:通過 synchronized關鍵字來聲明synchronized 塊。

語法如下:??

synchronized(syncObject) {  //允許訪問控制的代碼  
}  

? ? ? ?synchronized 塊是這樣一個代碼塊,其中的代碼必須獲得對象 syncObject (如前所述,可以是類實例或類)的鎖方能執行,具體機制同前所述。由于可以針對任意代碼塊,且可任意指定上鎖的對象,故靈活性較高。


java中synchronized用法


? ? ? ?打個比方:一個object就像一個大房子,大門永遠打開。房子里有 很多房間(也就是方法)。這些房間有上鎖的(synchronized方法), 和不上鎖之分(普通方法)。房門口放著一把鑰匙(key),這把鑰匙可以打開所有上鎖的房間。另外我把所有想調用該對象方法的線程比喻成想進入這房子某個 房間的人。所有的東西就這么多了,下面我們看看這些東西之間如何作用的。

? ? ? ?在此我們先來明確一下我們的前提條件。該對象至少有一個synchronized方法,否則這個key還有啥意義。當然也就不會有我們的這個主題了。

? ? ? ?一個人想進入某間上了鎖的房間,他來到房子門口,看見鑰匙在那兒(說明暫時還沒有其他人要使用上鎖的 房間)。于是他走上去拿到了鑰匙,并且按照自己 的計劃使用那些房間。注意一點,他每次使用完一次上鎖的房間后會馬上把鑰匙還回去。即使他要連續使用兩間上鎖的房間,中間他也要把鑰匙還回去,再取回來。

? ? ? ?因此,普通情況下鑰匙的使用原則是:“隨用隨借,用完即還。”

? ? ? ?這時其他人可以不受限制的使用那些不上鎖的房間,一個人用一間可以,兩個人用一間也可以,沒限制。但是如果當某個人想要進入上鎖的房間,他就要跑到大門口去看看了。有鑰匙當然拿了就走,沒有的話,就只能等了。

? ? ? ?要是很多人在等這把鑰匙,等鑰匙還回來以后,誰會優先得到鑰匙?Not guaranteed。象前面例子里那個想連續使用兩個上鎖房間的家伙,他中間還鑰匙的時候如果還有其他人在等鑰匙,那么沒有任何保證這家伙能再次拿到。 (JAVA規范在很多地方都明確說明不保證,象Thread.sleep()休息后多久會返回運行,相同優先權的線程那個首先被執行,當要訪問對象的鎖被 釋放后處于等待池的多個線程哪個會優先得到,等等。我想最終的決定權是在JVM,之所以不保證,就是因為JVM在做出上述決定的時候,絕不是簡簡單單根據 一個條件來做出判斷,而是根據很多條。而由于判斷條件太多,如果說出來可能會影響JAVA的推廣,也可能是因為知識產權保護的原因吧。SUN給了個不保證 就混過去了。無可厚非。但我相信這些不確定,并非完全不確定。因為計算機這東西本身就是按指令運行的。即使看起來很隨機的現象,其實都是有規律可尋。學過 計算機的都知道,計算機里隨機數的學名是偽隨機數,是人運用一定的方法寫出來的,看上去隨機罷了。另外,或許是因為要想弄的確定太費事,也沒多大意義,所 以不確定就不確定了吧。)

再來看看同步代碼塊和同步方法有小小的不同。

? ? ? ?1.從尺寸上講,同步代碼塊比同步方法小。你可以把同步代碼塊看成是沒上鎖房間里的一塊用帶鎖的屏風隔開的空間。

? ? ? ?2.同步代碼塊還可以人為的指定獲得某個其它對象的key。就像是指定用哪一把鑰匙才能開這個屏風的鎖,你可以用本房的鑰匙;你也可以指定用另一個房子的鑰匙才能開,這樣的話,你要跑到另一棟房子那兒把那個鑰匙拿來,并用那個房子的鑰匙來打開這個房子的帶鎖的屏風。

? ? ? ?記住你獲得的那另一棟房子的鑰匙,并不影響其他人進入那棟房子沒有鎖的房間。

? ? ? ?為什么要使用同步代碼塊呢?我想應該是這樣的:首先對程序來講同步的部分很影響運行效率,而一個方法通常是先創建一些局部變量,再對這些變量做一些 操作,如運算,顯示等等;而同步所覆蓋的代碼越多,對效率的影響就越嚴重。因此我們通常盡量縮小其影響范圍。

? ? ? ?如何做?同步代碼塊。我們只把一個方法中該同 步的地方同步,比如運算。

? ? ? ?另外,同步代碼塊可以指定鑰匙這一特點有個額外的好處,是可以在一定時期內霸占某個對象的key。還記得前面說過普通情況下鑰匙的使用原則嗎。現在不是普通情況了。你所取得的那把鑰匙不是永遠不還,而是在退出同步代碼塊時才還。

? ? ? ?還用前面那個想連續用兩個上鎖房間的家伙打比方。怎樣才能在用完一間以后,繼續使用另一間呢。用同步代碼塊吧。先創建另外一個線程,做一個同步代碼 塊,把那個代碼塊的鎖指向這個房子的鑰匙。然后啟動那個線程。只要你能在進入那個代碼塊時抓到這房子的鑰匙,你就可以一直保留到退出那個代碼塊。也就是說 你甚至可以對本房內所有上鎖的房間遍歷,甚至再sleep(10*60*1000),而房門口卻還有1000個線程在等這把鑰匙呢。很過癮吧。

? ? ? ?在此對sleep()方法和鑰匙的關聯性講一下。一個線程在拿到key后,且沒有完成同步的內容時,如果被強制sleep()了,那key還一直在 它那兒。直到它再次運行,做完所有同步內容,才會歸還key。記住,那家伙只是干活干累了,去休息一下,他并沒干完他要干的事。為了避免別人進入那個房間 把里面搞的一團糟,即使在睡覺的時候他也要把那唯一的鑰匙戴在身上。

? ? ? ?最后,也許有人會問,為什么要一把鑰匙通開,而不是一個鑰匙一個門呢?我想這純粹是因為復雜性問題。一個鑰匙一個門當然更安全,但是會牽扯好多問題。鑰匙 的產生,保管,獲得,歸還等等。其復雜性有可能隨同步方法的增加呈幾何級數增加,嚴重影響效率。這也算是一個權衡的問題吧。為了增加一點點安全性,導致效 率大大降低,是多么不可取啊。

synchronized的一個簡單例子:

public class TextThread {public static void main(String[] args) { TxtThread tt = new TxtThread(); new Thread(tt).start(); new Thread(tt).start(); new Thread(tt).start(); new Thread(tt).start(); } 
}class TxtThread implements Runnable { int num = 100; String str = new String();public void run() { synchronized (str) { while (num > 0) {try { Thread.sleep(1); } catch (Exception e) { e.getMessage(); } System.out.println(Thread.currentThread().getName() + "this is " + num--); } } } 
}

上面的例子中為了制造一個時間差,也就是出錯的機會,使用了Thread.sleep(10)

? ? ? ?Java對多線程的支持與同步機制深受大家的喜愛,似乎看起來使用了synchronized關鍵字就可以輕松地解決多線程共享數據同步問題。到底如何?――還得對synchronized關鍵字的作用進行深入了解才可定論。

? ? ? ?總的說來,synchronized關鍵字可以作為函數的修飾符,也可作為函數內的語句,也就是平時說的同步方法和同步語句塊。如果再細的分類,synchronized可作用于instance變量、object reference(對象引用)、static函數和class literals(類名稱字面常量)身上。

在進一步闡述之前,我們需要明確幾點:

? ? ? ?A.無論synchronized關鍵字加在方法上還是對象上,它取得的鎖都是對象,而不是把一段代碼或函數當作鎖――而且同步方法很可能還會被其他線程的對象訪問。

? ? ? ?B.每個對象只有一個鎖(lock)與之相關聯。

? ? ? ?C.實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。

接著來討論synchronized用到不同地方對代碼產生的影響:

假設P1、P2是同一個類的不同對象,這個類中定義了以下幾種情況的同步塊或同步方法,P1、P2就都可以調用它們。

1. 把synchronized當作函數修飾符時。

示例代碼如下:

Public synchronized void methodAAA(){//….
}
? ? ? ?這也就是同步方法,那這時synchronized鎖定的是哪個對象呢?它鎖定的是調用這個同步方法對象。也就是說,當一個對象P1在不同的線程中執行這個同步方法時,它們之間會形成互斥,達到同步的效果。但是這個對象所屬的Class所產生的另一對象P2卻可以任意調用這個被加了synchronized關鍵字的方法。

上邊的示例代碼等同于如下代碼:

public void methodAAA(){synchronized (this){      // (1)//……}
}
? ? ? ?(1)處的this指的是什么呢?它指的就是調用這個方法的對象,如P1。可見同步方法實質是將synchronized作用于object reference。――那個拿到了P1對象鎖的線程,才可以調用P1的同步方法,而對P2而言,P1這個鎖與它毫不相干,程序也可能在這種情形下擺脫同步機制的控制,造成數據混亂。

2.同步塊。

示例代碼如下:

public void method3(SomeObject so){synchronized(so){ //……}
}
? ? ? ?這時,鎖就是so這個對象,誰拿到這個鎖誰就可以運行它所控制的那段代碼。當有一個明確的對象作為鎖時,就可以這樣寫程序,但當沒有明確的對象作為鎖,只是想讓一段代碼同步時,可以創建一個特殊的instance變量(它得是一個對象)來充當鎖:

class Foo implements Runnable{private byte[] lock = new byte[0]; // 特殊的instance變量Public void methodA() {synchronized(lock) { //…… }}//……
}
注:零長度的byte數組對象創建起來將比任何對象都經濟――查看編譯后的字節碼:生成零長度的byte[]對象只需3條操作碼,而Object lock= new Object()則需要7行操作碼。

3.將synchronized作用于static 函數。

示例代碼如下:

Class Foo {public synchronized static void methodAAA(){   // 同步的static 函數  //… }public void methodBBB() {synchronized(Foo.class)   // class literal(類名稱字面常量)} 
}

? ? ? ?代碼中的methodBBB()方法是把class literal作為鎖的情況,它和同步的static函數產生的效果是一樣的,取得的鎖很特別,是當前調用這個方法的對象所屬的類(Class,而不再是由這個Class產生的某個具體對象了)。

? ? ? ?記得在《Effective Java》一書中看到過將 Foo.class和 P1.getClass()用于作同步鎖還不一樣,不能用P1.getClass()來達到鎖這個Class的目的。P1指的是由Foo類產生的對象。

可以推斷:

? ? ? ?如果一個類中定義了一個synchronized的static函數A,也定義了一個synchronized 的instance函數B,那么這個類的同一對象Obj在多線程中分別訪問A和B兩個方法時,不會構成同步,因為它們的鎖都不一樣。A方法的鎖是Obj這個對象,而B的鎖是Obj所屬的那個Class。

小結如下:

搞清楚synchronized鎖定的是哪個對象,就能幫助我們設計更安全的多線程程序。

還有一些技巧可以讓我們對共享資源的同步訪問更加安全:

? ? ? ?1. 定義private 的instance變量+它的 get方法,而不要定義public/protected的instance變量。如果將變量定義為public,對象在外界可以繞過同步方法的控制而直接取得它,并改動它。這也是JavaBean的標準實現方式之一。

? ? ? ?2. 如果instance變量是一個對象,如數組或ArrayList什么的,那上述方法仍然不安全,因為當外界對象通過get方法拿到這個instance對象的引用后,又將其指向另一個對象,那么這個private變量也就變了,豈不是很危險。 這個時候就需要將get方法也加上synchronized同步,并且,只返回這個private對象的clone()――這樣,調用端得到的就是對象副本的引用了。


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446996.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446996.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446996.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++:MAC安裝Boost庫文件并且使用CLion開發

boost的filestem庫 C在17版本的標準庫中引入了一個filesystem庫&#xff0c;用來處理文件路徑&#xff0c;以及文件訪問。很多編譯器對filesystem庫的支持還不是很好。為了解決這個問題&#xff0c;可以臨時使用boost::filesystem來替代。其實C17標準中的filesystem庫就是從bo…

Java基礎——Java異常處理機制

一、引言 try…catch…finally恐怕是大家再熟悉不過的語句了&#xff0c;而且感覺用起來也是很簡單&#xff0c;邏輯上似乎也是很容易理解。不過&#xff0c;我親自體驗的“教訓”告訴我&#xff0c;這個東西可不是想象中的那么簡單、聽話。不信&#xff1f;那你看看下面的代碼…

clion在使用sqlite3的時候,顯示Undefined symbols for architecture x86_64錯誤的解決辦法

顯示Undefined symbols for architecture x86_64錯誤的原因 1、缺少靜態庫 環境&#xff1a;在模擬器上報錯但在真機上能運行成功&#xff0c;而且報的錯誤來自于第三方庫。原因&#xff1a;architecture x86_64 是指模擬器的架構&#xff0c;意思就是 Crypto 變量在模擬器架…

Java基礎——Java反射機制及IoC原理

一、概念 主要是指程序可以訪問&#xff0c;檢測和修改它本身狀態或行為的一種能力&#xff0c;并能根據自身行為的狀態和結果&#xff0c;調整或修改應用所描述行為的狀態和相關的語義。在java中&#xff0c;只要給定類的名字&#xff0c; 那么就可以通過反射機制來獲得類的所…

Ubuntu boost庫文件安裝編譯

簡單介紹 Boost庫是為C語言標準庫提供擴展的一些C程序庫的總稱&#xff0c;由Boost社區組織開發、維護.Boost向來有準標準庫之稱&#xff0c;很多新特性例如智能指針等都是先在boost中實現&#xff0c;后來被吸收到標準庫之中. Boost實現了日志、算法、日期、地理、數學、線程…

Java基礎——類加載機制及原理

一、什么是類的加載&#xff1f; 類的加載指的是將類的.class文件中的二進制數據讀入到內存中&#xff0c;將其放在運行時數據區的方法區內&#xff0c;然后在堆區創建一個java.lang.Class對象&#xff0c;用來封裝類在方法區內的數據結構。類的加載的最終產品是位于堆區中的Cl…

在Ubuntu環境下使用vcpkg安裝sqlite_orm包文件

Ubuntu安裝vcpkg 從github下載vcpkg的安裝包&#xff0c;在usr/local路徑下面執行如下命令 git clone https://github.com/Microsoft/vcpkg.git cd vcpkg //進入源碼目錄 ./bootstrap-vcpkg.sh //執行./bootstrap-vcpkg.sh進行編譯安裝&#xff0c;這個過程很慢 編譯安裝好…

finally語句與return語句的執行順序

網上有很多人探討Java中異常捕獲機制try...catch...finally塊中的finally語句是不是一定會被執行&#xff1f;很多人都說不是&#xff0c;當然他們的回答是正確的&#xff0c;經過我試驗&#xff0c;至少有兩種情況下finally語句是不會被執行的&#xff1a; try語句沒有被執行到…

window電腦查看ssh公鑰,以及將自己的公鑰添加到Github等類似網站

查看本機的ssh公鑰 使用命令 cd ~/.ssh使用命令 ls 可以看到 id_rsa id_rsa.pub known_hosts 三個文件&#xff0c;此處需要的是id_rsa.pub文件使用命令 cat id_rsa.pub 查看文件的內容拷貝這段內容 添加自己的公鑰 進入賬戶的設置頁面參照如下步驟&#xff0c;進入SSH Key…

java八大排序算法

一、概述 排序有內部排序和外部排序&#xff0c;內部排序是數據記錄在內存中進行排序&#xff0c;而外部排序是因排序的數據很大&#xff0c;一次不能容納全部的排序記錄&#xff0c;在排序過程中需要訪問外存。 我們這里說說八大排序就是內部排序。 當n較大&#xff0c;則應采…

密鑰安全性討論之密鑰分層管理結構

密鑰分層管理結構 密鑰的安全管理通常采用層次化的保護方法。密鑰管理分層管理機制將密鑰分為三層&#xff0c;即根密鑰、密鑰加密密鑰和工作密鑰下層密鑰為上層密鑰提供加密保護&#xff0c;采用分層的密鑰結構有助于密鑰的管理滿足本規范的要求 工作密鑰 工作密鑰對本地保存…

windows安裝 Git Large File Storage大文件下載工具ge

下載地址 導航到 git-lfs.github.com 并單擊Download開始下載git-lfs的用法指南 驗證安裝成功 打開Git Bash驗證安裝成功&#xff0c;使用命令 git lfs install &#xff0c;如果出現 >Git LFS initlized&#xff0c;就代表安裝成功參考鏈接 安裝 Git Large File Storag…

Java基礎——volatile關鍵字解析

簡介volatile關鍵字雖然從字面上理解起來比較簡單&#xff0c;但是要用好不是一件容易的事情。由于volatile關鍵字是與Java的內存模型有關的&#xff0c;因此在講述volatile關鍵之前&#xff0c;我們先來了解一下與內存模型相關的概念和知識&#xff0c;然后分析了volatile關鍵…

Linux ubuntu對于cmake的版本更新

問題產生 在ubuntu環境下運行C代碼&#xff0c;工程文件中CMakeLists文件顯示要求cmake的版本最低是3.15&#xff0c;但是我的本地版本是3.11&#xff0c;雖然修改CMakelists文件為3.11也是可以編譯通過&#xff0c;但是潛在的問題是未知的。 查看本地cmake的版本 cmake --ve…

Java基礎——Java IO詳解

一、概述 1、Java IO Java IO即Java 輸入輸出系統。不管我們編寫何種應用&#xff0c;都難免和各種輸入輸出相關的媒介打交道&#xff0c;其實和媒介進行IO的過程是十分復雜的&#xff0c;這要考慮的因素特別多&#xff0c;比如我們要考慮和哪種媒介進行IO&#xff08;文件、控…

Java基礎——Java NIO詳解(二)

一、簡介 在我的上一篇文章Java NIO詳解&#xff08;一&#xff09;中介紹了關于標準輸入輸出NIO相關知識&#xff0c; 本篇將重點介紹基于網絡編程NIO&#xff08;異步IO&#xff09;。 二、異步IO 異步 I/O 是一種沒有阻塞地讀寫數據的方法。通常&#xff0c;在代碼進行 rea…

Java基礎——Java NIO詳解(一)

一、基本概念 1、I/0簡介 I/O即輸入輸出&#xff0c;是計算機與外界世界的一個借口。IO操作的實際主題是操作系統。在java編程中&#xff0c;一般使用流的方式來處理IO&#xff0c;所有的IO都被視作是單個字節的移動&#xff0c;通過stream對象一次移動一個字節。流IO負責把對象…

MAC上Git安裝與GitHub基本使用

參考鏈接 MAC上Git安裝與GitHub基本使用

Java基礎——深入理解Java線程池

簡介 我們使用線程的時候就去創建一個線程&#xff0c;這樣實現起來非常簡便&#xff0c;但是就會有一個問題&#xff1a; 如果并發的線程數量很多&#xff0c;并且每個線程都是執行一個時間很短的任務就結束了&#xff0c;這樣頻繁創建線程就會大大降低系統的效率&#xff0c;…