1. 程式人生 > >core Java基礎知識匯總

core Java基礎知識匯總

java基礎

collection和collections有什麽區別?

collection是一個接口集合,它提供了一系列對集合對象進行操作的通用接口方法,設計這個接口的目的是為各種不同的集合提供一個統一的接口方法。

collections是集合類的一個包裝類,它提供了一系列靜態的方法和對集合進行索引、排序、線程安全化等操作,而大多數方法是用來進行處理線性表。collections不能被實例化,它如同一個工具類,服務於collection框架,當調用collection類中的方法時,如果對應的collection對象為null,則會拋出nullponiterException.

線程是什麽?進程是什麽?它們有什麽區別和聯系?

線程是程序執行過程中,可以執行一段程序代碼的執行單元,在java語言中,線程的狀態有:運行,就緒,掛起,結束。

進程是一段正在執行的程序,線程有時也被稱為輕量級的進程,一個進程中通常有多個線程,各個線程在運行過程中,會共享程序的內存空間(代碼段、數據段、堆空間)以及進程級的資源(比如打開的文件),但是各個線程之間都有自己的棧空間。

在操作系統的層面上,進程是程序運行的基本單位,一個進程中通常都有多個線程在互不影響的並發執行。那麽為什麽要使用多線程呢?

使用多線程的優點是:

1.使用多線程可以減少程序的響應時間。

2.創建線程比進程的開銷更小。

3.多cpu和多核本來就可以運行多線程。

4.使用多線程可以簡化程序,便於程序的理解和維護,可以將復雜的問題轉化為簡單的多線程來執行。

同步是什麽?異步是什麽?

在多線程環境中,經常會遇到資源共享的問題。即多個線程調用同一個資源時,它們會按某種先後順序以確保每個時段只有一個線程調用資源,否則,將會出現無法預料的結果。在這種情況下就必須對數據進行同步,例如多個線程同時對同一數據進行寫操作,線程A需要使用某個資源時,而這個資源正在被B使用中,只有當線程B結束對資源的使用後,線程A才能使用該資源,同步機制可以保證資源的安全。

想要實現同步操作,就必須獲得對象的鎖,鎖可以確保每個時段只有一個線程進入臨界區(訪問互斥資源的代碼塊),並且在這個鎖釋放之前,其他線程不能進入臨界區,如果還有其他線程想要獲得該對象的鎖,只能進入等待隊列等待,只有當擁有該對象的鎖的線程退出臨界區時,等待區內運行級別最高的鎖才能進入臨界區,使用共享的代碼。

java為同步機制提供了語言級的支持,可以通過直接調用sychronized關鍵字來實現同步,但同步也不是“萬金油”。它是以很大的系統開銷作為代價,使用同步有時候會造成死鎖。所以同步控制並非越多越好,應避免無謂的使用同步。實現同步的方法有兩種:一種是通過代碼塊實現同步,另一種是通過調用方法實現同步。

異步類似於非阻塞,由於每個線程都包含運行時所需的數據或方法,所以在進行輸入輸出處理時,不需要關心其他線程的行為和狀態,也不需要等輸入輸出處理完成後在返回,如果程序在對象上調用一個非常耗時間的方法返回時,而且也不需要等待返回,這是就需要異步編程,異步可以提高程序的效率。

舉個生活中的例子,同步就是我叫你吃飯,你馬上和我一起走去吃飯,而異步是我叫你吃飯,你可以先在一起吃,也可以之後再吃,也可以不吃。

如何實現多線程?

java虛擬機允許程序並發的運行多個線程,那麽如何實現多線程呢,主要有以下3種方法:

1.繼承Thread類,重寫run()方法。

thread類本質上也是Runnable的一個實例,它是線程的實例,並且開啟線程的唯一方法就是調用thread類的start()方法,start()方法是一個native(本地)方法,它將啟動一個新線程並執行run()方法(thread類的run方法是一個空方法),這種方式通過自定義直接extend Thread類,並重寫run方法,就可以創建新的線程並使用自定義的run方法,需要註意的是,開啟線程並不是直接執行多線程的代碼,而是將多線程設置為可運行太,具體什麽時候開啟多線程有操作系統控制。

2.實現Runnable接口,並且實現該接口的run()方法。

(1)自定義類並實現Runnable接口,實現該接口的run()方法

(2)創建一個對象thread,用實現Runnable的對象作為參數實例化Thread

(3)調用thread的start()方法。

其實,不管通過多線程還是實現runnable接口,都是調用thread的API來處理多線程。

3.實現callable接口,重寫call()方法。

callable接口是execute框架的一個功能類,它的功能和Runnable類似,但是比runnanble的功能更加強大,主要表現在以下三點:

(1)callabble在任務結束後會有一個返回值,而runnable沒有。

(2)callable中的call方法可以拋出異常,而runnable中的run()方法不能拋出異常。

(3)使用callable會產生一個future對象,這個對象是異步計算的結果,它提供了檢查計算是否完成的方法,線程屬於異步計算模型,所以它不能從其他線程中獲得函數的返回值,在這種情況下,就可以使用future來監視目標線程調用call方法的情況,當調用future中的get()方法時,線程會處於阻塞狀態,直到call結束返回結果。

以上3種方法,前兩種執行完都沒有返回值,只有最後一種是帶返回值的。當需要實現多線程時,推薦使用的是實現runnable接口,原因主要是:首先,thread類提供了很多方法供派生類調用或重寫,只有run()方法是必須重寫的,run方法中實現線程的主要功能。這當然是實現Runnabel接口的必需的方法,其次,很多java開發人員認為只有加強或者修改時才會發生繼承,所以thread和實現runnnable接口的效果一樣,在這種該情況下最好通過實現runnanble接口來實現多線程。

多線程同步的實現方法有哪些?

當使用多線程訪問同一個資源時,非常容易出現線程安全的問題(例如,當多個線程同時對一個線程修改時,會出現一些線程對數據的修改丟失),在這種情況下就需要對數據進行同步,在java語言中,提供了3種實現多線程同步的方法。

<1>synchronized關鍵字

在java語言中,每個對象都有一個對象鎖與之關聯,該鎖表明對象在任何時候只能被一個線程所擁有,當一個線程需要調用一段synchronized代碼段時,需要獲取這個代碼段的鎖,才能繼續執行,執行完成後,釋放鎖。

在java語言中,sychronized關鍵字主要有兩種用法(synchronized方法和synchronized塊),也可以用來修飾可靜態方法和實例等,但是會影響程序的運行效率。

(1)在方法聲明前加上synchronized關鍵字,示例如下:

public synchronized void MutiThreadAccess()

在上面方法中,把需要共享的資源放到MutiThreadAccess()中,就能保證這個方法在同一時刻R只能被一個線程訪問,從而保證了多線程訪問的安全性。然而,當一個方法的方法體非常大時,使用synchronized方法會非常影響效率,為了解決這一問題,java提供了synchroonized塊。

(2)synchronized塊,synchronized既可以把任意一段代碼設置為synchronized,也可以指定對象上鎖,有非常高的靈活性。代碼示例如下:

synchronized(syncObject){

//訪問syncObject代碼

}

2.wait()與notify()方法。

當使用synchronized修飾共享資源時,如果一個線程A1在執行一個synchronized代碼,另外一個線程也要執行同一個對象的同一段sychronized代碼,線程a2要等到線程a1執行完成後才能繼續執行,這時就可以調用對象的wait()方法和notify()方法。

在synchronized代碼被執行過程中,線程可以調用對象的wait()方法,釋放對象鎖,進入等待狀態,並且可以調用對象的notify()方法或notifyAll()方法,通知線程獲取對象鎖。notify()方法只喚醒一個線程(等待隊列中的第一個),並且允許獲得對象鎖,notifyAll()方法會喚醒全部的線程允許它們獲得鎖(不保證所有的線程獲得鎖,讓它們去競爭)。

<2>Lock()方法。

jdk5提供了lock接口以及它的實現類Reentrantlock(重入鎖),Lock也可以用來實現多線程的同步,具體而言,主要通過以下方法進行實現:

(1)Lock(),通過阻塞線程來實現同步,如果獲取到鎖,會立即返回,如果鎖被其他線程擁有,會一直等待,知道獲取到鎖。

(2)tryLock().只是嘗試性的去獲取一下鎖。如果獲取到鎖,返回true,沒有獲取到鎖,則返回false。

(3)tryLock(long timeout,timeunit unit)。如果獲取到鎖,立即返回,如果沒有獲取到鎖,等到參數指定的時間單元,在等待過程中,如果獲取到了鎖,返回true,否則,返回false.

(4)lockInterruptibly(),如果獲取了鎖,立即返回,如果沒有獲取鎖,當前線程處於休眠狀態,直到獲得鎖,或者當前線程被別的線程中斷。它與lock方法最大的區別是如果lock()方法獲取不到鎖,會一直處於阻塞狀態,且會忽略Interrupt方法。

sleep()與wait()方法有什麽區別?

sleep()是用來將線程暫停執行的程序,wait()也是用來將線程暫停執行的程序,例如,當線程交互時,如果線程對一個同步對象x發出一個wait()調用請求,那麽該線程會暫停執行,

具體而言:sleep()與wait()方法的區別主要表示在一下幾個方面:

1.原理不同,sleep()方法是Thread類的靜態方法,是線程用來控制自身流程的,他會使線程暫停執行一段時間,而把執行機會讓給其他線程,等到計時時間一到,此線程會自動蘇醒。例如:當線程執行報時功能時,每一秒鐘打印出一個時間,那麽此時就需要在打印方法前面加上一個sleep()方法,以便讓自己每隔1s執行一次,該過程如同鬧鐘一樣。而wait()方法是object()方法,用於線程間的通信,這個方法會使當前擁有該對象鎖的進程等待,直到其他線程調用notify()方法(或notifyAll方法) 時才“醒”來,不過開發人員也可以給它指定一個時間,自動醒來,與wait()方法配套的方法還有還有notify和notifyAll()。

2.對鎖的處理機制不同,由於sleep()方法的主要作用是讓線程暫停執行一段時間,時間一到則自動恢復,不涉及線程間的通信,因此調用sleep()方法並不會釋放鎖,從而使線程所在對象中的其他synchronized數據可被別的線程使用。舉個例子來說:比如說小明拿遙控器的期間,可以用自己的sleep方法每隔10min調一次頻道,而在這10min裏,遙控器還在他的手上。

3.使用區域不同,由於wait()方法的特殊意義,因此它必須放在同步控制方法或者同步語句塊中使用,而sleep()方法則可以放在任何地方使用。

sleep()方法必須捕獲異常,而wait()、notify()以及notifyall()不需要捕獲異常,在sleep的過程中,有可能被其他對象調用它的interrupt(),產生InterruptedException異常。

由於sleep不會釋放“鎖標誌”,容易導致死鎖問題的發生,因此,一般情況下,不推薦使用sleep方法,而推薦使用wait()方法。

如何結束一個線程?

在java語言中,可以通過調用stop()方法或者suspend()方法來結束線程。當用thread.stop()來終止一個線程時,會停止這個線程的一切監視資源,而被這些監視資源監視的對象如果存在“不一致”,就會被其他線程所發現,從而會造成輸出結果不一定是原設定的。使用suspend()方法停止線程,則可能會發生死鎖(死鎖是兩個或者兩個以上的線程在資源競爭中造成相互等待的問題,如果沒有外界幫助,兩個線程都無法執行)。由於使用suspend時不需要釋放鎖,所以會造成一個問題:如果調用suspend()掛起一個帶鎖的線程,只有當鎖恢復是才會釋放。如果調用suspend(),其他線程想要獲得一個一樣的鎖,這種下就會造成死鎖。所以以上兩種不安全的終止線程的方法都不推薦。

那麽,如何終止一個線程呢?推薦讓線程自行結束進入dead狀態,即線程執行完run()方法,也就是說,使用一種方式讓線程結束執run()方法。具體而言,可以在線程加一個flag標誌來控制循環是否執行,從而使線程離run()方法的執行結束線程。實例如下

public class Thread implement(){

public static void main String(args[]){

public void stop{

flag=false;

}

public void run(){

while(flag);

//dosomething

}

}

}

在上述實例中,調用thread的stop方法雖然能夠終止線程,但是同樣存在問題,當線程處於非運行狀態時(當sleep()方法被調用或當wait()方法被調用或的那個I/O阻塞時),上面介紹的方法就不可用了。

此時可以用interrupt()方法來打破阻塞的情況,當interruot()方法被調用時,會拋出interruptException()異常,通過在run()中捕獲到該異常來讓線程安全退出。

synchronized()和lock()有什麽區別?

java提供了兩種鎖機制來實現資源的同步,synchronized()和lock(),其中synchronized()使用的事object對象的wait();notify();notifyAll(),而lock()是通過codition來進行線程之間的調度,來完成synchronized()實現的功能

具體而言,synchronized()和lock()主要有以下幾點不同:

(1)用法不同。在需要同步的對象前面加上synchronized,synchronized也可以放在方法,代碼塊中,被鎖定的對象放在括號中,而lock()必須顯示的指定起始位置和終止位置。synchronized是托管於JVM虛擬機去執行,而lock()是通過代碼實現的,lock()比synchronized有著更明確的線程語義。

(2)性能不同。在jdk5中增加了一個lock接口的實現ReeTrantLock(),它不僅擁有和synchronized相同的並發性和內存語義,還多了鎖投票、等候、定時鎖、中斷鎖等。就功能方面來說:當資源競爭中等時,synchronized的性能和lock()類似,當資源競爭很激烈時,synchronized的性能就會急速下降,而lock的性能基本保持不變。

(3)鎖機制不同。synchronized()獲得鎖和釋放鎖都是在塊結構中,當獲取多個鎖時,必須以相反的順序釋放,而且是自動釋放,不會因為發生異常而不釋放鎖造成死鎖,而lock則需要開發人員手動釋放,必須在final中釋放,否則會造成死鎖。同時,lock()比synchronized()有更強大的功能,它的trylock()方法可以用非阻塞的方式獲得鎖。

雖然synchronized和lock都可以實現多線程的同步,但是最好不要同時使用這兩種鎖,因為這兩種鎖的機制是不同的,它們都是獨立運行的,可以看作兩種不同的鎖,在運行時互不影響,但是運行結果可能不同。

什麽是守護線程?

java提供了兩種線程:守護線程和用戶線程,守護線程又被稱為“服務進程”、“精靈線程”、“後臺線程”,是指程序運行時在後臺提供通常服務的線程,它不是程序不可或缺的部分,通俗來講,它是jvm虛擬機中所有非守護線程的“保姆”。

用戶線程和守護線程幾乎一樣,唯一的不同之處是只要有一個用戶線程沒有結束,程序就不能結束,所有非守護線程結束了,程序也就結束了,Jvm也就結束了,原因是需要被守護的線程沒有了,守護線程也沒有工作了,所以程序就結束了,程序會“殺死”守護線程。通俗來講,只要程序中有一個非守護線程存在,程序就不會結束。

在java語言中,守護線程一般擁有較低的優先級,它並非只由jvm提供,用戶在編寫程序時自行設定守護線程,設定的方法是,在start()開啟線程之前調用對象的setDaemon(ture)方法,如果參數設置為false,表示設置為用戶進程模式。需要註意的是,如果一個守護線程中產生了其他線程,新的線程默認是守護線程,用戶線程也是這樣的。

join方法有什麽作用?

在java語言中,join方法的作用就是使調用該方法的線程在執行完run()方法之後,還能執行join()方法。簡單來說,就是合並兩個線程,用來實現同步的功能。具體來說,線程A調用線程A的join方法等待線程A的結束。比如線程A調用線程A的join(2000)等待線程A的結束,只等待2s。


本文出自 “java學習方向” 博客,謝絕轉載!

core Java基礎知識匯總