——每天寥寥的幾筆,堅持下去,將會是一份沉甸甸的積累。
老實說,多線程這塊學起來真不是很輕鬆。接下來,本人整理了下自己學習多線程這塊的一些核心內容(如果細講,恐不是一篇兩篇文章所能囊括的)
1.線程的概念: 通俗的理解,進程是一個大的運行的程序,而線程就是該程序裏面的一些子程序(功能)
專業的說,線程是CPU使用的基本單元,由線程ID,程序計數器,寄存器集合和棧組成,它與屬於同一進程的其他線程共享代碼段,數據段和其他資源。
從上面介紹中,要理解的核心暫時就是:共享數據。因此多個線程搶一份資源,結果就出現了線程安全,因此,線程的相關處理就很重要了。
2.無腦的使用(會使用是最低級別的,懂原理可居中層,理解底層源碼實現的可居高層,自己可以按需修改源碼並實現之的則乃高人也)
兩種創建線程的方法,
其一:繼承Thread類創建一子類,然後覆寫run方法,並new出該子類的實例對象(構造函數的參數就是你要共享,或許就是一個遙控器對象),最後調用start方法。
其二:一個類實現runnable接口,實現run方法,然後用這個類的對象作爲參數new出相關Thread對象,該對象就是該類的一個線程,調用start函數啓動線程。
3.多線程的高性能(多個同時併發執行),但也存在缺點,就是共享數據。
如何創建多線程共享一份數據,對應上面的兩種方法,實例代碼如下:
public class Share {//作爲共享數據的對象類
private int shareNum;
Share(int num){
this.shareNum = num;
}
public synchronized int getShareNum(){//由於該對象共享,必須添加synchronized關鍵字避免同時操作
return this.shareNum;
}
}
//方法一:繼承Thread類
public class Method01 extends Thread{
private Share share;
Method01(Share share){//構造函數傳入共享數據
this.share = share;
}
public void run(){
}
}
//方法二:實現runnable接口
public class Method02 implements Runnable{
private Share share;
Method02(Share share){//構造函數傳入共享數據
this.share = share;
}
public void run(){
}
}
public class Test{
//方法一
Share share = new Share(10);//建公共的共享數據對象,以下線程都已該對象爲參數
new Method01(share);//線程1,操作share
new Method01(share);//線程2,操作share
new Method01(share);//線程3,操作share
new Method01(share);//線程4,操作share
//方法二
Runnable method02 = new Method02(share);//以公共對象share作爲參數構造公共的runnable對象method02,然後以下線程都以這個共享的runnable對象爲參數
new Thread(method02);//線程1,操作method02
new Thread(method02);//線程2,操作method02
new Thread(method02);//線程3,操作method02
new Thread(method02);//線程4,操作method02
總結:其實方法二就是把方法一中的runnable接口對象給抽取出來了。
}
4.synchronized的注意點。
說這個關鍵字之前,大家必須清楚一個事實:java中的每一個對象都有一個內部鎖。線程A要調用該對象的synchronized的方法時,必須獲得該對象的鎖,而一旦拿到鎖,其他線程就拿不到改鎖,也就不能調用該方法,也就實現了阻塞的功能。
明白上面的概念,其實使用上沒啥難度:
其一:是直接加到方法返回類型前,則默認擁有了this對象的內部鎖;
其二:是同步阻塞,即
<span style="font-size:14px;">synchronized(obj){}//則擁有obj對象的鎖,該對象是程序員自己建出來的“虛擬鎖”</span>
但是,
但是,
有一點要注意,對於第一種方法——直接加到方法返回類型前的,由於默認擁有了this對象的內部鎖,因此該線程佔據了該類所有帶synchronized關鍵字前綴的方法的使用。而想避免這種情況出現,就可以選擇使用多個上面提到的虛擬鎖,不同的方法用第二種方法控制不同的虛擬鎖。比如:
public class A{
private Object obj1;
private Object obj2;
void B(){
synchronized(obj1){
//to-do-something
}
}
void C(){
synchronized(obj2){
//to-do-something
}
}
//這樣方法B和C就不耦合了
}
線程的知識遠不止這些。。。初級知識就不多寫了,中級知識——有關中斷,notify,notifyall,wait的下一篇文章再介紹吧。