java多線程應用實現方法

之前沒有寫筆記的習慣,如今慢慢的發現及時總結是多麼的重要了,呵呵。雖然才大二,可是也快要畢業了,要加油了。 
這一篇文章主要關於java多線程,主要仍是以例子來驅動的。由於講解多線程的書籍和文章已經不少了,因此我也很差意思多說,呵呵、你們能夠去參考一些那些書籍。我這個文章主要關於實際的一些問題。同時也算是我之後複習的資料吧,。呵呵你們多多指教。 
同時但願多結交一些技術上的朋友。謝謝。 
---------------------------------------------------------------------------------------------------------------------------------------------------- 
java中的多線程 
在java中要想實現多線程,有兩種手段,一種是繼續Thread類,另一種是實現Runable接口。 
對於直接繼承Thread的類來講,代碼大體框架是: html

複製代碼代碼以下:

class 類名 extends Thread{ 
方法1; 
方法2; 
… 
public void run(){ 
// other code… 

屬性1; 
屬性2; 

 

}java


先看一個簡單的例子:算法

複製代碼代碼以下:

/** 
* @author Rollen-Holt 繼承Thread類,直接調用run方法 
* */ 
class hello extends Thread {

 

public hello() {編程

}後端

public hello(String name) { 
this.name = name; 
}安全

public void run() { 
for (int i = 0; i < 5; i++) { 
System.out.println(name + "運行 " + i); 

}微信

public static void main(String[] args) { 
hello h1=new hello("A"); 
hello h2=new hello("B"); 
h1.run(); 
h2.run(); 
}數據結構

private String name; 
}多線程


【運行結果】: 
A運行 0 
A運行 1 
A運行 2 
A運行 3 
A運行 4 
B運行 0 
B運行 1 
B運行 2 
B運行 3 
B運行 4 
咱們會發現這些都是順序執行的,說明咱們的調用方法不對,應該調用的是start()方法。 
當咱們把上面的主函數修改成以下所示的時候: 架構

複製代碼代碼以下:

public static void main(String[] args) { 
hello h1=new hello("A"); 
hello h2=new hello("B"); 
h1.start(); 
h2.start(); 
}


而後運行程序,輸出的可能的結果以下: 
A運行 0 
B運行 0 
B運行 1 
B運行 2 
B運行 3 
B運行 4 
A運行 1 
A運行 2 
A運行 3 
A運行 4 
由於須要用到CPU的資源,因此每次的運行結果基本是都不同的,呵呵。 
注意:雖然咱們在這裏調用的是start()方法,可是實際上調用的仍是run()方法的主體。 
那麼:爲何咱們不能直接調用run()方法呢? 
個人理解是:線程的運行須要本地操做系統的支持。 
若是你查看start的源代碼的時候,會發現: 

複製代碼代碼以下:

public synchronized void start() { 
/** 
* This method is not invoked for the main method thread or "system" 
* group threads created/set up by the VM. Any new functionality added 
* to this method in the future may have to also be added to the VM. 

* A zero status value corresponds to state "NEW". 
*/ 
if (threadStatus != 0 || this != me) 
throw new IllegalThreadStateException(); 
group.add(this); 
start0(); 
if (stopBeforeStart) { 
stop0(throwableFromStop); 


private native void start0();


注意我用紅色加粗的那一條語句,說明此處調用的是start0()。而且這個這個方法用了native關鍵字,次關鍵字表示調用本地操做系統的函數。由於多線程的實現須要本地操做系統的支持。 
可是start方法重複調用的話,會出現java.lang.IllegalThreadStateException異常。

經過實現Runnable接口: 
大體框架是: 

複製代碼代碼以下:

class 類名 implements Runnable{ 
方法1; 
方法2; 
… 
public void run(){ 
// other code… 

屬性1; 
屬性2; 

 

}


來先看一個小例子吧: 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 實現Runnable接口 
* */ 
class hello implements Runnable {

 

public hello() {

}

public hello(String name) { 
this.name = name; 
}

public void run() { 
for (int i = 0; i < 5; i++) { 
System.out.println(name + "運行 " + i); 

}

public static void main(String[] args) { 
hello h1=new hello("線程A"); 
Thread demo= new Thread(h1); 
hello h2=new hello("線程B"); 
Thread demo1=new Thread(h2); 
demo.start(); 
demo1.start(); 
}

private String name; 
}


【可能的運行結果】: 
線程A運行 0 
線程B運行 0 
線程B運行 1 
線程B運行 2 
線程B運行 3 
線程B運行 4 
線程A運行 1 
線程A運行 2 
線程A運行 3 
線程A運行 4

 

關於選擇繼承Thread仍是實現Runnable接口? 
其實Thread也是實現Runnable接口的: 

複製代碼代碼以下:

class Thread implements Runnable { 
//… 
public void run() { 
if (target != null) { 
target.run(); 


}


其實Thread中的run方法調用的是Runnable接口的run方法。不知道你們發現沒有,Thread和Runnable都實現了run方法,這種操做模式其實就是代理模式。關於代理模式,我曾經寫過一個小例子呵呵,你們有興趣的話能夠看一下:http://www.cnblogs.com/rollenholt/archive/2011/08/18/2144847.html 
Thread和Runnable的區別: 
若是一個類繼承Thread,則不適合資源共享。可是若是實現了Runable接口的話,則很容易的實現資源共享。

複製代碼代碼以下:

/** 
* @author Rollen-Holt 繼承Thread類,不能資源共享 
* */ 
class hello extends Thread { 
public void run() { 
for (int i = 0; i < 7; i++) { 
if (count > 0) { 
System.out.println("count= " + count--); 


}

 

public static void main(String[] args) { 
hello h1 = new hello(); 
hello h2 = new hello(); 
hello h3 = new hello(); 
h1.start(); 
h2.start(); 
h3.start(); 
}

private int count = 5; 
}


【運行結果】: 
count= 5 
count= 4 
count= 3 
count= 2 
count= 1 
count= 5 
count= 4 
count= 3 
count= 2 
count= 1 
count= 5 
count= 4 
count= 3 
count= 2 
count= 1 
你們能夠想象,若是這個是一個買票系統的話,若是count表示的是車票的數量的話,說明並無實現資源的共享。 
咱們換爲Runnable接口: 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 繼承Thread類,不能資源共享 
* */ 
class hello implements Runnable { 
public void run() { 
for (int i = 0; i < 7; i++) { 
if (count > 0) { 
System.out.println("count= " + count--); 


}

 

public static void main(String[] args) { 
hello he=new hello(); 
new Thread(he).start(); 
}

private int count = 5; 
}


【運行結果】: 
count= 5 
count= 4 
count= 3 
count= 2 
count= 1

 

總結一下吧: 
實現Runnable接口比繼承Thread類所具備的優點: 
1):適合多個相同的程序代碼的線程去處理同一個資源 
2):能夠避免java中的單繼承的限制 
3):增長程序的健壯性,代碼能夠被多個線程共享,代碼和數據獨立。

因此,本人建議你們勁量實現接口。 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 
* 取得線程的名稱 
* */ 
class hello implements Runnable { 
public void run() { 
for (int i = 0; i < 3; i++) { 
System.out.println(Thread.currentThread().getName()); 

}

 

public static void main(String[] args) { 
hello he = new hello(); 
new Thread(he,"A").start(); 
new Thread(he,"B").start(); 
new Thread(he).start(); 

}


【運行結果】: 






Thread-0 
Thread-0 
Thread-0 
說明若是咱們沒有指定名字的話,系統自動提供名字。 
提醒一下你們:main方法其實也是一個線程。在java中因此的線程都是同時啓動的,至於何時,哪一個先執行,徹底看誰先獲得CPU的資源。

 

在java中,每次程序運行至少啓動2個線程。一個是main線程,一個是垃圾收集線程。由於每當使用java命令執行一個類的時候,實際上都會啓動一個JVM,每個jVM實習在就是在操做系統中啓動了一個進程。 
判斷線程是否啓動 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 判斷線程是否啓動 
* */ 
class hello implements Runnable { 
public void run() { 
for (int i = 0; i < 3; i++) { 
System.out.println(Thread.currentThread().getName()); 

}

 

public static void main(String[] args) { 
hello he = new hello(); 
Thread demo = new Thread(he); 
System.out.println("線程啓動以前---》" + demo.isAlive()); 
demo.start(); 
System.out.println("線程啓動以後---》" + demo.isAlive()); 

}  


【運行結果】 
線程啓動以前---》false 
線程啓動以後---》true 
Thread-0 
Thread-0 
Thread-0 
主線程也有可能在子線程結束以前結束。而且子線程不受影響,不會由於主線程的結束而結束。

 

線程的強制執行: 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 線程的強制執行 
* */ 
class hello implements Runnable { 
public void run() { 
for (int i = 0; i < 3; i++) { 
System.out.println(Thread.currentThread().getName()); 

}

 

public static void main(String[] args) { 
hello he = new hello(); 
Thread demo = new Thread(he,"線程"); 
demo.start(); 
for(int i=0;i<50;++i){ 
if(i>10){ 
try{ 
demo.join(); //強制執行demo 
}catch (Exception e) { 
e.printStackTrace(); 


System.out.println("main 線程執行-->"+i); 


}


【運行的結果】: 
main 線程執行-->0 
main 線程執行-->1 
main 線程執行-->2 
main 線程執行-->3 
main 線程執行-->4 
main 線程執行-->5 
main 線程執行-->6 
main 線程執行-->7 
main 線程執行-->8 
main 線程執行-->9 
main 線程執行-->10 
線程 
線程 
線程 
main 線程執行-->11 
main 線程執行-->12 
main 線程執行-->13 
...

 

線程的休眠: 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 線程的休眠 
* */ 
class hello implements Runnable { 
public void run() { 
for (int i = 0; i < 3; i++) { 
try { 
Thread.sleep(2000); 
} catch (Exception e) { 
e.printStackTrace(); 

System.out.println(Thread.currentThread().getName() + i); 

}

 

public static void main(String[] args) { 
hello he = new hello(); 
Thread demo = new Thread(he, "線程"); 
demo.start(); 

}


【運行結果】:(結果每隔2s輸出一個) 
線程0 
線程1 
線程2

 

線程的中斷: 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 線程的中斷 
* */ 
class hello implements Runnable { 
public void run() { 
System.out.println("執行run方法"); 
try { 
Thread.sleep(10000); 
System.out.println("線程完成休眠"); 
} catch (Exception e) { 
System.out.println("休眠被打斷"); 
return; //返回到程序的調用處 

System.out.println("線程正常終止"); 
}

 

public static void main(String[] args) { 
hello he = new hello(); 
Thread demo = new Thread(he, "線程"); 
demo.start(); 
try{ 
Thread.sleep(2000); 
}catch (Exception e) { 
e.printStackTrace(); 

demo.interrupt(); //2s後中斷線程 

}


【運行結果】: 
執行run方法 
休眠被打斷

 

在java程序中,只要前臺有一個線程在運行,整個java程序進程不會小時,因此此時能夠設置一個後臺線程,這樣即便java進程小時了,此後臺線程依然可以繼續運行。 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 後臺線程 
* */ 
class hello implements Runnable { 
public void run() { 
while (true) { 
System.out.println(Thread.currentThread().getName() + "在運行"); 

}

 

public static void main(String[] args) { 
hello he = new hello(); 
Thread demo = new Thread(he, "線程"); 
demo.setDaemon(true); 
demo.start(); 

}


雖然有一個死循環,可是程序仍是能夠執行完的。由於在死循環中的線程操做已經設置爲後臺運行了。 
線程的優先級: 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 線程的優先級 
* */ 
class hello implements Runnable { 
public void run() { 
for(int i=0;i<5;++i){ 
System.out.println(Thread.currentThread().getName()+"運行"+i); 

}

 

public static void main(String[] args) { 
Thread h1=new Thread(new hello(),"A"); 
Thread h2=new Thread(new hello(),"B"); 
Thread h3=new Thread(new hello(),"C"); 
h1.setPriority(8); 
h2.setPriority(2); 
h3.setPriority(6); 
h1.start(); 
h2.start(); 
h3.start();


}


【運行結果】: 
A運行0 
A運行1 
A運行2 
A運行3 
A運行4 
B運行0 
C運行0 
C運行1 
C運行2 
C運行3 
C運行4 
B運行1 
B運行2 
B運行3 
B運行4 
。可是請讀者不要誤覺得優先級越高就先執行。誰先執行仍是取決於誰先去的CPU的資源、

 

另外,主線程的優先級是5. 
線程的禮讓。 
在線程操做中,也可使用yield()方法,將一個線程的操做暫時交給其餘線程執行。 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 線程的優先級 
* */ 
class hello implements Runnable { 
public void run() { 
for(int i=0;i<5;++i){ 
System.out.println(Thread.currentThread().getName()+"運行"+i); 
if(i==3){ 
System.out.println("線程的禮讓"); 
Thread.currentThread().yield(); 


}

 

public static void main(String[] args) { 
Thread h1=new Thread(new hello(),"A"); 
Thread h2=new Thread(new hello(),"B"); 
h1.start(); 
h2.start();


}


A運行0 
A運行1 
A運行2 
A運行3 
線程的禮讓 
A運行4 
B運行0 
B運行1 
B運行2 
B運行3 
線程的禮讓 
B運行4

 


同步和死鎖: 
【問題引出】:好比說對於買票系統,有下面的代碼: 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 
* */ 
class hello implements Runnable { 
public void run() { 
for(int i=0;i<10;++i){ 
if(count>0){ 
try{ 
Thread.sleep(1000); 
}catch(InterruptedException e){ 
e.printStackTrace(); 

System.out.println(count--); 


}

 

public static void main(String[] args) { 
hello he=new hello(); 
Thread h1=new Thread(he); 
Thread h2=new Thread(he); 
Thread h3=new Thread(he); 
h1.start(); 
h2.start(); 
h3.start(); 

private int count=5; 
}


【運行結果】: 






-1 
這裏出現了-1,顯然這個是錯的。,應該票數不能爲負值。 
若是想解決這種問題,就須要使用同步。所謂同步就是在統一時間段中只有有一個線程運行, 
其餘的線程必須等到這個線程結束以後才能繼續執行。 
【使用線程同步解決問題】 
採用同步的話,可使用同步代碼塊和同步方法兩種來完成。

 

【同步代碼塊】: 
語法格式: 
synchronized(同步對象){ 
//須要同步的代碼 

可是通常都把當前對象this做爲同步對象。 
好比對於上面的買票的問題,以下: 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 
* */ 
class hello implements Runnable { 
public void run() { 
for(int i=0;i<10;++i){ 
synchronized (this) { 
if(count>0){ 
try{ 
Thread.sleep(1000); 
}catch(InterruptedException e){ 
e.printStackTrace(); 

System.out.println(count--); 



}

 

public static void main(String[] args) { 
hello he=new hello(); 
Thread h1=new Thread(he); 
Thread h2=new Thread(he); 
Thread h3=new Thread(he); 
h1.start(); 
h2.start(); 
h3.start(); 

private int count=5; 
}


【運行結果】:(每一秒輸出一個結果) 





【同步方法】 
也能夠採用同步方法。 
語法格式爲synchronized 方法返回類型 方法名(參數列表){ 
// 其餘代碼 

如今,咱們採用同步方法解決上面的問題。 

複製代碼代碼以下:

/** 
* @author Rollen-Holt 
* */ 
class hello implements Runnable { 
public void run() { 
for (int i = 0; i < 10; ++i) { 
sale(); 

}

 

public synchronized void sale() { 
if (count > 0) { 
try { 
Thread.sleep(1000); 
} catch (InterruptedException e) { 
e.printStackTrace(); 

System.out.println(count--); 

}

public static void main(String[] args) { 
hello he = new hello(); 
Thread h1 = new Thread(he); 
Thread h2 = new Thread(he); 
Thread h3 = new Thread(he); 
h1.start(); 
h2.start(); 
h3.start(); 
}

private int count = 5; 
}


【運行結果】(每秒輸出一個) 





提醒一下,當多個線程共享一個資源的時候須要進行同步,可是過多的同步可能致使死鎖。 
此處列舉經典的生產者和消費者問題。 
【生產者和消費者問題】 
先看一段有問題的代碼。 

複製代碼代碼以下:

class Info {

 

public String getName() { 
return name; 
}

public void setName(String name) { 
this.name = name; 
}

public int getAge() { 
return age; 
}

public void setAge(int age) { 
this.age = age; 
}

private String name = "Rollen"; 
private int age = 20; 
}

/** 
* 生產者 
* */ 
class Producer implements Runnable{ 
private Info info=null; 
Producer(Info info){ 
this.info=info; 
}

public void run(){ 
boolean flag=false; 
for(int i=0;i<25;++i){ 
if(flag){ 
this.info.setName("Rollen"); 
try{ 
Thread.sleep(100); 
}catch (Exception e) { 
e.printStackTrace(); 

this.info.setAge(20); 
flag=false; 
}else{ 
this.info.setName("chunGe"); 
try{ 
Thread.sleep(100); 
}catch (Exception e) { 
e.printStackTrace(); 

this.info.setAge(100); 
flag=true; 




/** 
* 消費者類 
* */ 
class Consumer implements Runnable{ 
private Info info=null; 
public Consumer(Info info){ 
this.info=info; 
}

public void run(){ 
for(int i=0;i<25;++i){ 
try{ 
Thread.sleep(100); 
}catch (Exception e) { 
e.printStackTrace(); 

System.out.println(this.info.getName()+"<---->"+this.info.getAge()); 


}

/** 
* 測試類 
* */ 
class hello{ 
public static void main(String[] args) { 
Info info=new Info(); 
Producer pro=new Producer(info); 
Consumer con=new Consumer(info); 
new Thread(pro).start(); 
new Thread(con).start(); 

}


【運行結果】: 
Rollen<---->100 
chunGe<---->20 
chunGe<---->100 
Rollen<---->100 
chunGe<---->20 
Rollen<---->100 
Rollen<---->100 
Rollen<---->100 
chunGe<---->20 
chunGe<---->20 
chunGe<---->20 
Rollen<---->100 
chunGe<---->20 
Rollen<---->100 
chunGe<---->20 
Rollen<---->100 
chunGe<---->20 
Rollen<---->100 
chunGe<---->20 
Rollen<---->100 
chunGe<---->20 
Rollen<---->100 
chunGe<---->20 
Rollen<---->100 
chunGe<---->20 
你們能夠從結果中看到,名字和年齡並無對於。

 

那麼如何解決呢? 
<!--[if !supportLists]-->1) <!--[endif]-->加入同步 
<!--[if !supportLists]-->2) <!--[endif]-->加入等待和喚醒 
先來看看加入同步會是如何。 

複製代碼代碼以下:

class Info {

 

public String getName() { 
return name; 
}

public void setName(String name) { 
this.name = name; 
}

public int getAge() { 
return age; 
}

public void setAge(int age) { 
this.age = age; 
}

public synchronized void set(String name, int age){ 
this.name=name; 
try{ 
Thread.sleep(100); 
}catch (Exception e) { 
e.printStackTrace(); 

this.age=age; 
}

public synchronized void get(){ 
try{ 
Thread.sleep(100); 
}catch (Exception e) { 
e.printStackTrace(); 

System.out.println(this.getName()+"<===>"+this.getAge()); 

private String name = "Rollen"; 
private int age = 20; 
}

/** 
* 生產者 
* */ 
class Producer implements Runnable { 
private Info info = null;

Producer(Info info) { 
this.info = info; 
}

public void run() { 
boolean flag = false; 
for (int i = 0; i < 25; ++i) { 
if (flag) {

this.info.set("Rollen", 20); 
flag = false; 
} else { 
this.info.set("ChunGe", 100); 
flag = true; 



}

/** 
* 消費者類 
* */ 
class Consumer implements Runnable { 
private Info info = null;

public Consumer(Info info) { 
this.info = info; 
}

public void run() { 
for (int i = 0; i < 25; ++i) { 
try { 
Thread.sleep(100); 
} catch (Exception e) { 
e.printStackTrace(); 

this.info.get(); 


}

/** 
* 測試類 
* */ 
class hello { 
public static void main(String[] args) { 
Info info = new Info(); 
Producer pro = new Producer(info); 
Consumer con = new Consumer(info); 
new Thread(pro).start(); 
new Thread(con).start(); 

}


【運行結果】: 
Rollen<===>20 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
Rollen<===>20 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
ChunGe<===>100 
從運行結果來看,錯亂的問題解決了,如今是Rollen 對應20,ChunGe對於100 
,可是仍是出現了重複讀取的問題,也確定有重複覆蓋的問題。若是想解決這個問題,就須要使用Object類幫忙了、 
,咱們可使用其中的等待和喚醒操做。 
要完成上面的功能,咱們只須要修改Info類飢渴,在其中加上標誌位,而且經過判斷標誌位完成等待和喚醒的操做,代碼以下: 

複製代碼代碼以下:

class Info {

 

public String getName() { 
return name; 
}

public void setName(String name) { 
this.name = name; 
}

public int getAge() { 
return age; 
}

public void setAge(int age) { 
this.age = age; 
}

public synchronized void set(String name, int age){ 
if(!flag){ 
try{ 
super.wait(); 
}catch (Exception e) { 
e.printStackTrace(); 


this.name=name; 
try{ 
Thread.sleep(100); 
}catch (Exception e) { 
e.printStackTrace(); 

this.age=age; 
flag=false; 
super.notify(); 
}

public synchronized void get(){ 
if(flag){ 
try{ 
super.wait(); 
}catch (Exception e) { 
e.printStackTrace(); 

}

try{ 
Thread.sleep(100); 
}catch (Exception e) { 
e.printStackTrace(); 

System.out.println(this.getName()+"<===>"+this.getAge()); 
flag=true; 
super.notify(); 

private String name = "Rollen"; 
private int age = 20; 
private boolean flag=false; 
}

/** 
* 生產者 
* */ 
class Producer implements Runnable { 
private Info info = null;

Producer(Info info) { 
this.info = info; 
}

public void run() { 
boolean flag = false; 
for (int i = 0; i < 25; ++i) { 
if (flag) {

this.info.set("Rollen", 20); 
flag = false; 
} else { 
this.info.set("ChunGe", 100); 
flag = true; 



}

/** 
* 消費者類 
* */ 
class Consumer implements Runnable { 
private Info info = null;

public Consumer(Info info) { 
this.info = info; 
}

public void run() { 
for (int i = 0; i < 25; ++i) { 
try { 
Thread.sleep(100); 
} catch (Exception e) { 
e.printStackTrace(); 

this.info.get(); 


}

/** 
* 測試類 
* */ 
class hello { 
public static void main(String[] args) { 
Info info = new Info(); 
Producer pro = new Producer(info); 
Consumer con = new Consumer(info); 
new Thread(pro).start(); 
new Thread(con).start(); 

}


【程序運行結果】: 
Rollen<===>20 
ChunGe<===>100 
Rollen<===>20 
ChunGe<===>100 
Rollen<===>20 
ChunGe<===>100 
Rollen<===>20 
ChunGe<===>100 
Rollen<===>20 
ChunGe<===>100 
Rollen<===>20 
ChunGe<===>100 
Rollen<===>20 
ChunGe<===>100 
Rollen<===>20 
ChunGe<===>100 
Rollen<===>20 
ChunGe<===>100 
Rollen<===>20 
ChunGe<===>100 
Rollen<===>20 
ChunGe<===>100 
Rollen<===>20 
ChunGe<===>100 
Rollen<===>20 
先在看結果就能夠知道,以前的問題徹底解決。 
《完》 
PS(寫在後面): 
本人深知學的太差,因此但願你們能多多指點。另外,關於多線程其實有不少的知識,因爲目前我也就知道的不太多,寫了一些經常使用的。雖然在操做系統這門課上學了不少的線程和進程,好比銀行家算法等等的,之後有時間在補充,你們有什麼好資料能夠留個言,你們一塊兒分享一下,謝謝了。 

 

     
Java學習動力節點最新Java夜校教程全套
基於Java的微信平臺開發教程
62 課時 編程視頻 Java Node.js全棧開發
JAVA高級軟件架構師實戰培訓課程 私塾在線JAVA架構師培訓課程 116講視頻教程階段二 attach_img
源碼時代全套JavaSE入門視頻教程 2017最新JAVA基礎入門與進階全套視頻 attach_img
兩套JAVA NIA NIO專題培訓視頻教程 守望者+軟酷網兩套JAVA基礎NIO視頻教程 attach_img
孫宇老師Struts2+Hibernate4+Maven+EasyUI+SpringMvc+Spring+Mybatis+Maven整合課程 attach_img
動力節點2018最新Javase零基礎視頻教程
從零學習互聯網最前沿微框架Spring Boot教程全集 attach_img
JAVA高級軟件架構師實戰培訓課程 私塾在線JAVA架構師培訓課程 116講視頻教程階段二 attach_img
Java企業級電商項目架構演進之路 Tomcat集羣與Redis分佈式(更新至11章)
62 課時 編程視頻 Java Node.js全棧開發
Java語言數據結構與算法
Spring Boot企業微信點餐系統  ...2
Spring Security開發安全的REST服務
Java SSM淘淘商城12天電商項目
Java Spring帶先後端開發完整電商平臺  ...2
2017最新Java基礎入門與進階全套視頻
淘寶購買Java項目SpringMvc+Mybatis+Oracle+EasyUI採購系統視頻教程
極客學院 Docker全面解讀零基礎實戰 視頻教程
相關文章
相關標籤/搜索