1. 進程和線程有什麼區別
1、功能不同
進程是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。
線程是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。
2、工作原理不同
在早期面向進程設計的計算機結構中,進程是程序的基本執行實體;在當代面向線程設計的計算機結構中,進程是線程的容器。程序是指令、數據及其組織形式的描述,進程是程序的實體。
線程是獨立調度和分派的基本單位。線程可以為操作系統內核調度的內核線程,如Win32線程;由用戶進程自行調度的用戶線程,如Linux平台的POSIX Thread;或者由內核與用戶進程,如Windows 7的線程,進行混合調度。
3、作用不同
進程是操作系統中最基本、重要的概念。是多道程序系統出現後,為了刻畫系統內部出現的動態情況,描述系統內部各道程序的活動規律引進的一個概念,所有多道程序設計操作系統都建立在進程的基礎上。
通常在一個進程中可以包含若干個線程,它們可以利用進程所擁有的資源。在引入線程的操作系統中,通常都是把進程作為分配資源的基本單位,而把線程作為獨立運行和獨立調度的基本單位。
(1)java進程和線程的區別擴展閱讀
進程是由進程式控制制塊,程序段,數據段三部分組成。一個進程可以包含若干線程(Thread),線程可以幫助應用程序同時做幾件事(比如一個線程向磁碟寫入文件,另一個則接收用戶的按鍵操作並及時做出反應,互相不幹擾)。
在程序被運行後,系統首先要做的就是為該程序進程建立一個默認線程,然後程序可以根據需要自行添加或刪除相關的線程。是可並發執行的程序。
在一個數據集合上的運行過程,是系統進行資源分配和調度的一個獨立單位,也是稱活動、路徑或任務,它有兩方面性質:活動性、並發性。
進程可以劃分為運行,阻塞,就緒三種狀態,並隨一定條件而相互轉化,就緒運行,運行阻塞,阻塞就緒。
進程為應用程序的運行實例,是應用程序的一次動態執行。看似高深,我們可以簡單地理解為:它是操作系統當前運行的執行程序。
在系統當前運行的執行程序里包括:系統管理計算機個體和完成各種操作所必需的程序;用戶開啟、執行的額外程序,當然也包括用戶不知道,而自動運行的非法程序(它們就有可能是病毒程序)。
2. 進程和線程的聯系和區別 抽象類與介面的區別
定義:
一、進程是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,是系統進行資源分配和調度的一個獨立單位。
二、線程是進程的一個實體,是CPU調度和分派的基本單位,他是比進程更小的能獨立運行的基本單位,線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),一個線程可以創建和撤銷另一個線程;
進程和線程的關系:
(1)一個線程只能屬於一個進程,而一個進程可以有多個線程,但至少有一個線程。
(2)資源分配給進程,同一進程的所有線程共享該進程的所有資源。
(3)線程在執行過程中,需要協作同步。不同進程的線程間要利用消息通信的辦法實現同步。
(4)處理機分給線程,即真正在處理機上運行的是線程。
(5)線程是指進程內的一個執行單元,也是進程內的可調度實體。
線程與進程的區別:
(1)調度:線程作為調度和分配的基本單位,進程作為擁有資源的基本單位。
(2)並發性:不僅進程之間可以並發執行,同一個進程的多個線程之間也可以並發執行。
(3)擁有資源:進程是擁有資源的一個獨立單位,線程不擁有系統資源,但可以訪問隸屬於進程的資源。
(4)系統開銷:在創建或撤銷進程的時候,由於系統都要為之分配和回收資源,導致系統的明顯大於創建或撤銷線程時的開銷。但進程有獨立的地址空間,進程崩潰後,在保護模式下不會對其他的進程產生影響,而線程只是一個進程中的不同的執行路徑。線程有自己的堆棧和局部變數,但線程之間沒有單獨的地址空間,一個線程死掉就等於整個進程死掉,所以多進程的程序要比多線程的程序健壯,但是在進程切換時,耗費的資源較大,效率要差些。
線程的劃分尺度小於進程,使得多線程程序的並發性高。
另外,進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,從而極大的提高了程序運行效率。
線程在執行過程中,每個獨立的線程有一個程序運行的入口,順序執行序列和程序的出口。但是線程不能夠獨立執行,必須依存在應用程序中,有應用程序提供多個線程執行控制。
從邏輯角度看,多線程的意義子啊與一個應用程序中,有多個執行部分可以同時執行。但操作系統並沒有將多個線程看做多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別。
線程是一個進程中一個執行流程
一個進程中有多個線程
執行一個java程序,最少有兩個線程,一個main主線程,還有一個守護線程(垃圾回收機制)
java中定義線程:
a.集成Thread類
b.實現Runnable介面 好(實現並可繼承)
抽象類與介面:
定義:介面是對動作的抽象,抽象類是對根源的抽象。
抽象類表示的是,這個對象是什麼。介面表示的是,這個對象能做什麼。比如,男人,女人,這兩個類(如果是類的話……),他們的抽象類是人。說明,他們都是人。
人可以吃東西,狗也可以吃東西,你可以把「吃東西」定義成一個介面,然後讓這些類去實現它.
所以,在高級語言上,一個類只能繼承一個類(抽象類)(正如人不可能同時是生物和非生物),但是可以實現多個介面(吃飯介面、走路介面)。
第一點. 介面是抽象類的變體,介面中所有的方法都是抽象的。而抽象類是聲明方法的存在而不去實現它的類。
第二點. 介面可以多繼承,抽象類不行
第三點. 介面定義方法,不能實現,而抽象類可以實現部分方法。
第四點. 介面中基本數據類型為static 而抽類象不是的。
當你關注一個事物的本質的時候,用抽象類;當你關注一個操作的時候,用介面。
抽象類的功能要遠超過介面,但是,定義抽象類的代價高。因為高級語言來說(從實際設計上來說也是)每個類只能繼承一個類。在這個類中,你必須繼承或編寫出其所有子類的
所有共性。雖然介面在功能上會弱化許多,但是它只是針對一個動作的描述。而且你可以在一個類中同時實現多個介面。在設計階段會降低難度的。
3. java 中線程與進程的區別是什麼
進程,是針對於操作系統而言的
線程,是java中一個重要的類,主要用來多個方法一起執行
進程和線程都是由操作系統所體會的程序運行的基本單元,系統利用該基本單元實現系統對應用的並發性。進程和線程的區別在於:
簡而言之,一個程序至少有一個進程,一個進程至少有一個線程.
線程的劃分尺度小於進程,使得多線程程序的並發性高。
另外,進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,從而極大地提高了程序的運行效率。
線程在執行過程中與進程還是有區別的。每個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。但是線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。
從邏輯角度來看,多線程的意義在於一個應用程序中,有多個執行部分可以同時執行。但操作系統並沒有將多個線程看做多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別。
進程是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位.
線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.
一個線程可以創建和撤銷另一個線程;同一個進程中的多個線程之間可以並發執行.
4. JAVA 的線程這塊咋整啊,咋也學不明白啊~~
線程!我把我理解的簡單的很你說說也許有點用
理解線程和進程的區別 先可以理解為線程組成進程
首先也是類是個
他的實例化有一般兩種方法:一是繼承thread一種是實現借口runable
他的方法有start sleep run wait stop等
一、進程與應用程序的區別
進程(Process)是最初定義在Unix等多用戶、多任務操作系統環境下用於表示應用程序在內存環境中基本執行單元的概念。以Unix操作系統為例,進程是Unix操作系統環境中的基本成分、是系統資源分配的基本單位。Unix操作系統中完成的幾乎所有用戶管理和資源分配等工作都是通過操作系統對應用程序進程的控制來實現的。
C、C++、Java等語言編寫的源程序經相應的編譯器編譯成可執行文件後,提交給計算機處理器運行。這時,處在可執行狀態中的應用程序稱為進程。從用戶角度來看,進程是應用程序的一個執行過程。從操作系統核心角度來看,進程代表的是操作系統分配的內存、CPU時間片等資源的基本單位,是為正在運行的程序提供的運行環境。進程與應用程序的區別在於應用程序作為一個靜態文件存儲在計算機系統的硬碟等存儲空間中,而進程則是處於動態條件下由操作系統維護的系統資源管理實體。多任務環境下應用程序進程的主要特點包括:
●進程在執行過程中有內存單元的初始入口點,並且進程存活過程中始終擁有獨立的內存地址空間;
●進程的生存期狀態包括創建、就緒、運行、阻塞和死亡等類型;
●從應用程序進程在執行過程中向CPU發出的運行指令形式不同,可以將進程的狀態分為用戶態和核心態。處於用戶態下的進程執行的是應用程序指令、處於核心態下的應用程序進程執行的是操作系統指令。
在Unix操作系統啟動過程中,系統自動創建swapper、init等系統進程,用於管理內存資源以及對用戶進程進行調度等。在Unix環境下無論是由操作系統創建的進程還要由應用程序執行創建的進程,均擁有唯一的進程標識(PID)。
二、進程與Java線程的區別
應用程序在執行過程中存在一個內存空間的初始入口點地址、一個程序執行過程中的代碼執行序列以及用於標識進程結束的內存出口點地址,在進程執行過程中的每一時間點均有唯一的處理器指令與內存單元地址相對應。
Java語言中定義的線程(Thread)同樣包括一個內存入口點地址、一個出口點地址以及能夠順序執行的代碼序列。但是進程與線程的重要區別在於線程不能夠單獨執行,它必須運行在處於活動狀態的應用程序進程中,因此可以定義線程是程序內部的具有並發性的順序代碼流。
Unix操作系統和Microsoft Windows操作系統支持多用戶、多進程的並發執行,而Java語言支持應用程序進程內部的多個執行線程的並發執行。多線程的意義在於一個應用程序的多個邏輯單元可以並發地執行。但是多線程並不意味著多個用戶進程在執行,操作系統也不把每個線程作為獨立的進程來分配獨立的系統資源。進程可以創建其子進程,子進程與父進程擁有不同的可執行代碼和數據內存空間。而在用於代表應用程序的進程中多個線程共享數據內存空間,但保持每個線程擁有獨立的執行堆棧和程序執行上下文(Context)。
基於上述區別,線程也可以稱為輕型進程 (Light Weight Process,LWP)。不同線程間允許任務協作和數據交換,使得在計算機系統資源消耗等方面非常廉價。
線程需要操作系統的支持,不是所有類型的計算機都支持多線程應用程序。Java程序設計語言將線程支持與語言運行環境結合在一起,提供了多任務並發執行的能力。這就好比一個人在處理家務的過程中,將衣服放到洗衣機中自動洗滌後將大米放在電飯鍋里,然後開始做菜。等菜做好了,飯熟了同時衣服也洗好了。
需要注意的是:在應用程序中使用多線程不會增加 CPU 的數據處理能力。只有在多CPU 的計算機或者在網路計算體系結構下,將Java程序劃分為多個並發執行線程後,同時啟動多個線程運行,使不同的線程運行在基於不同處理器的Java虛擬機中,才能提高應用程序的執行效率。
另外,如果應用程序必須等待網路連接或資料庫連接等數據吞吐速度相對較慢的資源時,多線程應用程序是非常有利的。基於Internet的應用程序有必要是多線程類型的,例如,當開發要支持大量客戶機的伺服器端應用程序時,可以將應用程序創建成多線程形式來響應客戶端的連接請求,使每個連接用戶獨佔一個客戶端連接線程。這樣,用戶感覺伺服器只為連接用戶自己服務,從而縮短了伺服器的客戶端響應時間。
三、Java語言的多線程程序設計方法
利用Java語言實現多線程應用程序的方法很簡單。根據多線程應用程序繼承或實現對象的不同可以採用兩種方式:一種是應用程序的並發運行對象直接繼承Java的線程類Thread;另外一種方式是定義並發執行對象實現Runnable介面。
繼承Thread類的多線程程序設計方法
Thread 類是JDK中定義的用於控制線程對象的類,在該類中封裝了用於進行線程式控制制的方法。見下面的示例代碼:
[code]//Consumer.java
import java.util.*;
class Consumer extends Thread
{
int nTime;
String strConsumer;
public Consumer(int nTime, String strConsumer)
{
this.nTime = nTime;
this.strConsumer = strConsumer;
}
public void run()
{
while(true)
{
try
{
System.out.println("Consumer name:"+strConsumer+"\n");
Thread.sleep(nTime);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
static public void main(String args[])
{
Consumer aConsumer = new Consumer (1000, "aConsumer");
aConsumer.start();
Consumer bConsumer = new Consumer (2000, "bConsumer");
bConsumer.start();
Consumer cConsumer = new Consumer (3000, "cConsumer ");
cConsumer.start();
}
} [/code]
從上面的程序代碼可以看出:多線程執行地下Consumer繼承Java語言中的線程類Thread並且在main方法中創建了三個Consumer對象的實例。當調用對象實例的start方法時,自動調用Consumer類中定義的run方法啟動對象線程運行。線程運行的結果是每間隔nTime時間列印出對象實例中的字元串成員變數strConsumer的內容。
可以總結出繼承Thread類的多線程程序設計方法是使應用程序類繼承Thread類並且在該類的run方法中實現並發性處理過程。
實現Runnable介面的多線程程序設計方法
Java語言中提供的另外一種實現多線程應用程序的方法是多線程對象實現Runnable介面並且在該類中定義用於啟動線程的run方法。這種定義方式的好處在於多線程應用對象可以繼承其它對象而不是必須繼承Thread類,從而能夠增加類定義的邏輯性。
實現Runnable介面的多線程應用程序框架代碼如下所示:
//Consumer.java
import java.util.*;
class Consumer implements Runnable
{
… …
public Consumer(int nTime, String strConsumer){… …}
public void run(){… …}
static public void main(String args[])
{
Thread aConsumer = new Thread(new Consumer(1000, "aConsumer"));
aConsumer.start();
//其它對象實例的運行線程
//… …
}
}
從上述代碼可以看出:該類實現了Runnable介面並且在該類中定義了run方法。這種多線程應用程序的實現方式與繼承Thread類的多線程應用程序的重要區別在於啟動多線程對象的方法設計方法不同。在上述代碼中,通過創建Thread對象實例並且將應用對象作為創建Thread類實例的參數。
四、線程間的同步
Java應用程序的多個線程共享同一進程的數據資源,多個用戶線程在並發運行過程中可能同時訪問具有敏感性的內容。在Java中定義了線程同步的概念,實現對共享資源的一致性維護。下面以筆者最近開發的移動通信計費系統中線程間同步控制方法,說明Java語言中多線程同步方式的實現過程。
在沒有多線程同步控制策略條件下的客戶賬戶類定義框架代碼如下所示:
public class RegisterAccount
{
float fBalance;
//客戶繳費方法
public void deposit(float fFees){ fBalance += fFees; }
//通話計費方法
public void withdraw(float fFees){ fBalance -= fFees; }
… …
}
讀者也許會認為:上述程序代碼完全能夠滿足計費系統實際的需要。確實,在單線程環境下該程序確實是可靠的。但是,多進程並發運行的情況是怎樣的呢?假設發生這種情況:客戶在客戶服務中心進行繳費的同時正在利用移動通信設備僅此通話,客戶通話結束時計費系統啟動計費進程,而同時服務中心的工作人員也提交繳費進程運行。讀者可以看到如果發生這種情況,對客戶賬戶的處理是不嚴肅的。
如何解決這種問題呢?很簡單,在RegisterAccount類方法定義中加上用於標識同步方法的關鍵字synchronized。這樣,在同步方法執行過程中該方法涉及的共享資源(在上述代碼中為fBalance成員變數)將被加上共享鎖,以確保在方法運行期間只有該方法能夠對共享資源進行訪問,直到該方法的線程運行結束打開共享鎖,其它線程才能夠訪問這些共享資源。在共享鎖沒有打開的時候其它訪問共享資源的線程處於阻塞狀態。
進行線程同步策略控制後的RegisterAccount類定義如下面代碼所示:
public class RegisterAccount
{
float fBalance;
public synchronized void deposit(float fFees){ fBalance += fFees; }
public synchronized void withdraw(float fFees){ fBalance -= fFees; }
… …
}
從經過線程同步機制定義後的代碼形式可以看出:在對共享資源進行訪問的方法訪問屬性關鍵字(public)後附加同步定義關鍵字synchronized,使得同步方法在對共享資源訪問的時候,為這些敏感資源附加共享鎖來控制方法執行期間的資源獨占性,實現了應用系統數據資源的一致性管理和維護。
五、 Java線程的管理
線程的狀態控制
在這里需要明確的是:無論採用繼承Thread類還是實現Runnable介面來實現應用程序的多線程能力,都需要在該類中定義用於完成實際功能的run方法,這個run方法稱為線程體(Thread Body)。按照線程體在計算機系統內存中的狀態不同,可以將線程分為創建、就緒、運行、睡眠、掛起和死亡等類型。這些線程狀態類型下線程的特徵為:
創建狀態:當利用new關鍵字創建線程對象實例後,它僅僅作為一個對象實例存在,JVM沒有為其分配CPU時間片等線程運行資源;
就緒狀態:在處於創建狀態的線程中調用start方法將線程的狀態轉換為就緒狀態。這時,線程已經得到除CPU時間之外的其它系統資源,只等JVM的線程調度器按照線程的優先順序對該線程進行調度,從而使該線程擁有能夠獲得CPU時間片的機會。
睡眠狀態:在線程運行過程中可以調用sleep方法並在方法參數中指定線程的睡眠時間將線程狀態轉換為睡眠狀態。這時,該線程在不釋放佔用資源的情況下停止運行指定的睡眠時間。時間到達後,線程重新由JVM線程調度器進行調度和管理。
掛起狀態:可以通過調用suspend方法將線程的狀態轉換為掛起狀態。這時,線程將釋放佔用的所有資源,由JVM調度轉入臨時存儲空間,直至應用程序調用resume方法恢復線程運行。
死亡狀態:當線程體運行結束或者調用線程對象的stop方法後線程將終止運行,由JVM收回線程佔用的資源。
在Java線程類中分別定義了相應的方法,用於在應用程序中對線程狀態進行控制和管理。
線程的調度
線程調用的意義在於JVM應對運行的多個線程進行系統級的協調,以避免多個線程爭用有限資源而導致應用系統死機或者崩潰。
為了線程對於操作系統和用戶的重要性區分開,Java定義了線程的優先順序策略。Java將線程的優先順序分為10個等級,分別用1-10之間的數字表示。數字越大表明線程的級別越高。相應地,在Thread類中定義了表示線程最低、最高和普通優先順序的成員變數MIN_PRIORITY、MAX_PRIORITY和NORMAL_PRIORITY,代表的優先順序等級分別為1、10和5。當一個線程對象被創建時,其默認的線程優先順序是5。
為了控制線程的運行策略,Java定義了線程調度器來監控系統中處於就緒狀態的所有線程。線程調度器按照線程的優先順序決定那個線程投入處理器運行。在多個線程處於就緒狀態的條件下,具有高優先順序的線程會在低優先順序線程之前得到執行。線程調度器同樣採用"搶占式"策略來調度線程執行,即當前線程執行過程中有較高優先順序的線程進入就緒狀態,則高優先順序的線程立即被調度執行。具有相同優先順序的所有線程採用輪轉的方式來共同分配CPU時間片。
在應用程序中設置線程優先順序的方法很簡單,在創建線程對象之後可以調用線程對象的setPriority方法改變該線程的運行優先順序,同樣可以調用getPriority方法獲取當前線程的優先順序。
在Java中比較特殊的線程是被稱為守護(Daemon)線程的低級別線程。這個線程具有最低的優先順序,用於為系統中的其它對象和線程提供服務。將一個用戶線程設置為守護線程的方式是在線程對象創建之前調用線程對象的setDaemon方法。典型的守護線程例子是JVM中的系統資源自動回收線程,它始終在低級別的狀態中運行,用於實時監控和管理系統中的可回收資源。
線程分組管理
Java定義了在多線程運行系統中的線程組(ThreadGroup)對象,用於實現按照特定功能對線程進行集中式分組管理。用戶創建的每個線程均屬於某線程組,這個線程組可以在線程創建時指定,也可以不指定線程組以使該線程處於默認的線程組之中。但是,一旦線程加入某線程組,該線程就一直存在於該線程組中直至線程死亡,不能在中途改變線程所屬的線程組。
當Java的Application應用程序運行時,JVM創建名稱為main的線程組。除非單獨指定,在該應用程序中創建的線程均屬於main線程組。在main線程組中可以創建其它名稱的線程組並將其它線程加入到該線程組中,依此類推,構成線程和線程組之間的樹型管理和繼承關系。
與線程類似,可以針對線程組對象進行線程組的調度、狀態管理以及優先順序設置等。在對線程組進行管理過程中,加入到某線程組中的所有線程均被看作統一的對象。
六、小結:
本文針對Java平台中線程的性質和應用程序的多線程策略進行了分析和講解。
與其它操作系統環境不同,Java運行環境中的線程類似於多用戶、多任務操作系統環境下的進程,但在進程和線程的運行及創建方式等方面,進程與Java線程具有明顯區別。
Unix操作系統環境下,應用程序可以利用fork函數創建子進程,但子進程與該應用程序進程擁有獨立的地址空間、系統資源和代碼執行單元,並且進程的調度是由操作系統來完成的,使得在應用進程之間進行通信和線程協調相對復雜。而Java應用程序中的多線程則是共享同一應用系統資源的多個並行代碼執行體,線程之間的通信和協調方法相對簡單。
可以說:Java語言對應用程序多線程能力的支持增強了Java作為網路程序設計語言的優勢,為實現分布式應用系統中多客戶端的並發訪問以及提高伺服器的響應效率奠定堅實基礎。
Java的線程編程非常簡單。但有時會看到一些關於線程的錯誤用法。下面列出一些應該注意的問題。
1.同步對象的恆定性
All java objects are references.
對於局部變數和參數來說,java裡面的int, float, double, boolean等基本數據類型,都在棧上。這些基本類型是無法同步的;java裡面的對象(根對象是Object),全都在堆里,指向對象的reference在棧上。
java中的同步對象,實際上是對於reference所指的「對象地址」進行同步。
需要注意的問題是,千萬不要對同步對象重新賦值。舉個例子。
class A implements Runnable{
Object lock = new Object();
void run(){
for(...){
synchronized(lock){
// do something
...
lock = new Object();
}
}
}
run函數裡面的這段同步代碼實際上是毫無意義的。因為每一次lock都給重新分配了新的對象的reference,每個線程都在新的reference同步。
大家可能覺得奇怪,怎麼會舉這么一個例子。因為我見過這樣的代碼,同步對象在其它的函數里被重新賦了新值。
這種問題很難查出來。
所以,一般應該把同步對象聲明為final.
final Object lock = new Object();
使用Singleton Pattern 設計模式來獲取同步對象,也是一種很好的選擇。
2.如何放置共享數據
實現線程,有兩種方法,一種是繼承Thread類,一種是實現Runnable介面。
上面舉的例子,採用實現Runnable介面的方法。本文推薦這種方法。
首先,把需要共享的數據放在一個實現Runnable介面的類裡面,然後,把這個類的實例傳給多個Thread的構造方法。這樣,新創建的多個Thread,都共同擁有一個Runnable實例,共享同一份數據。
如果採用繼承Thread類的方法,就只好使用static靜態成員了。如果共享的數據比較多,就需要大量的static靜態成員,令程序數據結構混亂,難以擴展。這種情況應該盡量避免。
編寫一段多線程代碼,處理一個稍微復雜點的問題。兩種方法的優劣,一試便知。
3.同步的粒度
線程同步的粒度越小越好,即,線程同步的代碼塊越小越好。盡量避免用synchronized修飾符來聲明方法。盡量使用synchronized(anObject)的方式,如果不想引入新的同步對象,使用synchronized(this)的方式。而且,synchronized代碼塊越小越好。
4.線程之間的通知
這里使用「通知」這個詞,而不用「通信」這個詞,是為了避免詞義的擴大化。
線程之間的通知,通過Object對象的wait()和notify() 或notifyAll() 方法實現。
下面用一個例子,來說明其工作原理:
假設有兩個線程,A和B。共同擁有一個同步對象,lock。
1.首先,線程A通過synchronized(lock) 獲得lock同步對象,然後調用lock.wait()函數,放棄lock同步對象,線程A停止運行,進入等待隊列。
2.線程B通過synchronized(lock) 獲得線程A放棄的lock同步對象,做完一定的處理,然後調用 lock.notify() 或者lock.notifyAll() 通知等待隊列裡面的線程A。
3.線程A從等待隊列裡面出來,進入ready隊列,等待調度。
4.線程B繼續處理,出了synchronized(lock)塊之後,放棄lock同步對象。
5.線程A獲得lock同步對象,繼續運行。
例子代碼如下:
public class SharedResource implements Runnable{
Object lock = new Object();
public void run(){
// 獲取當前線程的名稱。
String threadName = Thread.currentThread().getName();
if( 「A」.equals(threadName)){
synchronized(lock){ //線程A通過synchronized(lock) 獲得lock同步對象
try{
System.out.println(「 A gives up lock.」);
lock.wait(); // 調用lock.wait()函數,放棄lock同步對象,
// 線程A停止運行,進入等待隊列。
}catch(InterruptedException e){
}
// 線程A重新獲得lock同步對象之後,繼續運行。
System.out.println(「 A got lock again and continue to run.」);
} // end of synchronized(lock)
}
if( 「B」.equals(threadName)){
synchronized(lock){//線程B通過synchronized(lock) 獲得線程A放棄的lock同步對象
System.out.println(「B got lock.」);
lock.notify(); //通知等待隊列裡面的線程A,進入ready隊列,等待調度。
//線程B繼續處理,出了synchronized(lock)塊之後,放棄lock同步對象。
System.out.println(「B gives up lock.」);
} // end of synchronized(lock)
boolean hasLock = Thread.holdsLock(lock); // 檢查B是否擁有lock同步對象。
System.out.println(「B has lock ? -- 」 +hasLock); // false.
}
}
}
public class TestMain{
public static void main(){
Runnable resource = new SharedResource();
Thread A = new Thread(resource,」A」);
A.start();
// 強迫主線程停止運行,以便線程A開始運行。
try {
Thread.sleep(500);
}catch(InterruptedException e){
}
Thread B = new Thread(resource,」B」);
B.start();
}
}
5.跨類的同步對象
對於簡單的問題,可以把訪問共享資源的同步代碼都放在一個類裡面。
但是對於復雜的問題,我們需要把問題分為幾個部分來處理,需要幾個不同的類來處理問題。這時,就需要在不同的類中,共享同步對象。比如,在生產者和消費者之間共享同步對象,在讀者和寫者之間共享同步對象。
如何在不同的類中,共享同步對象。有幾種方法實現,
(1)前面講過的方法,使用static靜態成員,(或者使用Singleton Pattern.)
(2)用參數傳遞的方法,把同步對象傳遞給不同的類。
(3)利用字元串常量的「原子性」。
對於第三種方法,這里做一下解釋。一般來說,程序代碼中的字元串常量經過編譯之後,都具有唯一性,即,內存中不會存在兩份相同的字元串常量。
(通常情況下,C++,C語言程序編譯之後,也具有同樣的特性。)
比如,我們有如下代碼。
String A = 「atom」;
String B = 「atom」;
我們有理由認為,A和B指向同一個字元串常量。即,A==B。
注意,聲明字元串變數的代碼,不符合上面的規則。
String C= new String(「atom」);
String D = new String(「atom」);
這里的C和D的聲明是字元串變數的聲明,所以,C != D。
有了上述的認識,我們就可以使用字元串常量作為同步對象。
比如我們在不同的類中,使用synchronized(「myLock」), 「myLock」.wait(),「myLock」.notify(), 這樣的代碼,就能夠實現不同類之間的線程同步。
本文並不強烈推薦這種用法,只是說明,有這樣一種方法存在。
本文推薦第二種方法,(2)用參數傳遞的方法,把同步對象傳遞給不同的類。
給你網站
http://www.webpc8.com/Article/java/xc/
5. 鍦╦ava閲岄潰浠涔堟槸綰跨▼,浠涔堟槸涓葷嚎紼涓葷嚎紼嬪拰瀛愮嚎紼嬬殑鍏崇郴
棣栧厛錛宩ava閲岀殑綰跨▼娌℃湁涓誨拰瀛愮殑璇存硶錛屽彧鏈夌嚎紼嬩紭鍏堢駭鐨勮存硶,涔熻鎬綘璇寸殑鏄榪涚▼鍜岀嚎紼嬪惂錛屼笅闈㈡槸璇︾粏璧勬枡
綰跨▼鏄鎸囪繘紼嬪唴鐨勪竴涓鎵ц屽崟鍏,涔熸槸榪涚▼鍐呯殑鍙璋冨害瀹炰綋.涓庤繘紼嬬殑鍖哄埆:
(1)鍦板潃絀洪棿:榪涚▼鍐呯殑涓涓鎵ц屽崟鍏;榪涚▼鑷沖皯鏈変竴涓綰跨▼;瀹冧滑鍏變韓榪涚▼鐨勫湴鍧絀洪棿;鑰岃繘紼嬫湁鑷宸辯嫭絝嬬殑鍦板潃絀洪棿;
(2)璧勬簮鎷ユ湁:榪涚▼鏄璧勬簮鍒嗛厤鍜屾嫢鏈夌殑鍗曚綅,鍚屼竴涓榪涚▼鍐呯殑綰跨▼鍏變韓榪涚▼鐨勮祫婧
(3)綰跨▼鏄澶勭悊鍣ㄨ皟搴︾殑鍩烘湰鍗曚綅,浣嗚繘紼嬩笉鏄.
(4)浜岃呭潎鍙騫跺彂鎵ц.
榪涚▼鍜岀嚎紼嬮兘鏄鐢辨搷浣滅郴緇熸墍浣撲細鐨勭▼搴忚繍琛岀殑鍩烘湰鍗曞厓錛岀郴緇熷埄鐢ㄨュ熀鏈鍗曞厓瀹炵幇緋葷粺瀵瑰簲鐢ㄧ殑騫跺彂鎬с傝繘紼嬪拰綰跨▼鐨勫尯鍒鍦ㄤ簬錛
綆鑰岃█涔,涓涓紼嬪簭鑷沖皯鏈変竴涓榪涚▼,涓涓榪涚▼鑷沖皯鏈変竴涓綰跨▼.
綰跨▼鐨勫垝鍒嗗昂搴﹀皬浜庤繘紼嬶紝浣垮緱澶氱嚎紼嬬▼搴忕殑騫跺彂鎬ч珮銆
鍙﹀栵紝榪涚▼鍦ㄦ墽琛岃繃紼嬩腑鎷ユ湁鐙絝嬬殑鍐呭瓨鍗曞厓錛岃屽氫釜綰跨▼鍏變韓鍐呭瓨錛屼粠鑰屾瀬澶у湴鎻愰珮浜嗙▼搴忕殑榪愯屾晥鐜囥
綰跨▼鍦ㄦ墽琛岃繃紼嬩腑涓庤繘紼嬭繕鏄鏈夊尯鍒鐨勩傛瘡涓鐙絝嬬殑綰跨▼鏈変竴涓紼嬪簭榪愯岀殑鍏ュ彛銆侀『搴忔墽琛屽簭鍒楀拰紼嬪簭鐨勫嚭鍙c備絾鏄綰跨▼涓嶈兘澶熺嫭絝嬫墽琛岋紝蹇呴』渚濆瓨鍦ㄥ簲鐢ㄧ▼搴忎腑錛岀敱搴旂敤紼嬪簭鎻愪緵澶氫釜綰跨▼鎵ц屾帶鍒躲
浠庨昏緫瑙掑害鏉ョ湅錛屽氱嚎紼嬬殑鎰忎箟鍦ㄤ簬涓涓搴旂敤紼嬪簭涓錛屾湁澶氫釜鎵ц岄儴鍒嗗彲浠ュ悓鏃舵墽琛屻備絾鎿嶄綔緋葷粺騫舵病鏈夊皢澶氫釜綰跨▼鐪嬪仛澶氫釜鐙絝嬬殑搴旂敤錛屾潵瀹炵幇榪涚▼鐨勮皟搴﹀拰綆$悊浠ュ強璧勬簮鍒嗛厤銆傝繖灝辨槸榪涚▼鍜岀嚎紼嬬殑閲嶈佸尯鍒銆
榪涚▼鏄鍏鋒湁涓瀹氱嫭絝嬪姛鑳界殑紼嬪簭鍏充簬鏌愪釜鏁版嵁闆嗗悎涓婄殑涓嬈¤繍琛屾椿鍔,榪涚▼鏄緋葷粺榪涜岃祫婧愬垎閰嶅拰璋冨害鐨勪竴涓鐙絝嬪崟浣.
綰跨▼鏄榪涚▼鐨勪竴涓瀹炰綋,鏄疌PU璋冨害鍜屽垎媧劇殑鍩烘湰鍗曚綅,瀹冩槸姣旇繘紼嬫洿灝忕殑鑳界嫭絝嬭繍琛岀殑鍩烘湰鍗曚綅.綰跨▼鑷宸卞熀鏈涓婁笉鎷ユ湁緋葷粺璧勬簮,鍙鎷ユ湁涓鐐瑰湪榪愯屼腑蹇呬笉鍙灝戠殑璧勬簮(濡傜▼搴忚℃暟鍣,涓緇勫瘎瀛樺櫒鍜屾爤),浣嗘槸瀹冨彲涓庡悓灞炰竴涓榪涚▼鐨勫叾浠栫殑綰跨▼鍏變韓榪涚▼鎵鎷ユ湁鐨勫叏閮ㄨ祫婧.
涓涓綰跨▼鍙浠ュ壋寤哄拰鎾ら攢鍙︿竴涓綰跨▼;鍚屼竴涓榪涚▼涓鐨勫氫釜綰跨▼涔嬮棿鍙浠ュ苟鍙戞墽琛.
6. java面試中經常被問到的問題有哪些
java面試中經常被問到的問題有如下:
1、進程,線程,協程之間的區別是什麼?
簡而言之,進程是程序運行和資源分配的基本單位,一個程序至少有一個進程,一個進程至少有一個線程。進程在執行過程中擁有獨立的內存單元,而多個線程共享內存資源,減少切換次數,從而效率更高。線程是進程的一個實體,是cpu調度和分派的基本單位,是比程序更小的能獨立運行的基本單位。同一進程中的多個線程之間可以並發執行。
2、你了解守護線程嗎?它和非守護線程有什麼區別?
程序運行完畢,jvm會等待非守護線程完成後關閉,但是jvm不會等待守護線程。守護線程最典型的例子就是GC線程。
3、什麼是多線程上下文切換?
多線程的上下文切換是指CPU控制權由一個已經正在運行的線程切換到另外一個就緒並等待獲取CPU執行權的線程的過程。
4、創建兩種線程的方式?他們有什麼區別?
通過實現java.lang.Runnable或者通過擴展java.lang.Thread類。相比擴展Thread,實現Runnable介面可能更優.原因有二:Java不支持多繼承。因此擴展Thread類就代表這個子類不能擴展其他類。而實現Runnable介面的類還可能擴展另一個類。類可能只要求可執行即可,因此繼承整個Thread類的開銷過大。
5、Thread類中的start()和run()方法有什麼區別?
start()方法被用來啟動新創建的線程,而且start()內部調用了run()方法,這和直接調用run()方法的效果不一樣。當你調用run()方法的時候,只會是在原來的線程中調用,沒有新的線程啟動,start()方法才會啟動新線程。
7. Java基本概念之線程和進程有什麼區別
1.定義
進程:具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位.
線程:進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.
2.關系
一個線程可以創建和撤銷另一個線程;同一個進程中的多個線程之間可以並發執行.
相對進程而言,線程是一個更加接近於執行體的概念,它可以與同進程中的其他線程共享數據,但擁有自己的棧空間,擁有獨立的執行序列。
3.區別
進程和線程的主要差別在於它們是不同的操作系統資源管理方式。進程有獨立的地址空間,一個進程崩潰後,在保護模式下不會對其它進程產生影響,而線程只是一個進程中的不同執行路徑。線程有自己的堆棧和局部變數,但線程之間沒有單獨的地址空間,一個線程死掉就等於整個進程死掉,所以多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行並且又要共享某些變數的並發操作,只能用線程,不能用進程。
1) 簡而言之,一個程序至少有一個進程,一個進程至少有一個線程.
2) 線程的劃分尺度小於進程,使得多線程程序的並發性高。
3) 另外,進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,從而極大地提高了程序的運行效率。
4) 線程在執行過程中與進程還是有區別的。每個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。但是線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。
5) 從邏輯角度來看,多線程的意義在於一個應用程序中,有多個執行部分可以同時執行。但操作系統並沒有將多個線程看做多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別。
4.優缺點
線程和進程在使用上各有優缺點:
線程執行開銷小,但不利於資源的管理和保護;
而進程正相反。
同時,線程適合於在SMP機器上運行,而進程則可以跨機器遷移。