Java知識點總結

索引的實現方式

一、B+樹javascript

咱們常常聽到B+樹就是這個概念,用這個樹的目的和紅黑樹差很少,也是爲了儘可能保持樹的平衡,固然紅黑樹是二叉樹,但B+樹就不是二叉樹了,節點下面能夠有多個子節點,數據庫開發商會設置子節點數的一個最大值,這個值不會過小,因此B+樹通常來講比較矮胖,而紅黑樹就比較瘦高了。

關於B+樹的插入,刪除,會涉及到一些算法以保持樹的平衡,這裏就不詳述了。ORACLE的默認索引就是這種結構的。
若是常常須要同時對兩個字段進行AND查詢,那麼使用兩個單獨索引不如創建一個複合索引,由於兩個單獨索引一般數據庫只能使用其中一個,而使用複合索引由於索引自己就對應到兩個字段上的,效率會有很大提升。html

二、散列索引java

第二種索引叫作散列索引,就是經過散列函數來定位的一種索引,不過不多有單獨使用散列索引的,反而是散列文件組織用的比較多。

散列文件組織就是根據一個鍵經過散列計算把對應的記錄都放到同一個槽中,這樣的話相同的鍵值對應的記錄就必定是放在同一個文件裏了,也就減小了文件讀取的次數,提升了效率。
散列索引呢就是根據對應鍵的散列碼來找到最終的索引項的技術,其實和B樹就差很少了,也就是一種索引之上的二級輔助索引,我理解散列索引都是二級或更高級的稀疏索引,不然桶就太多了,效率也不會很高。mysql

三、位圖索引程序員

位圖索引是一種針對多個字段的簡單查詢設計一種特殊的索引,適用範圍比較小,只適用於字段值固定而且值的種類不多的狀況,好比性別,只能有男和女,或者級別,狀態等等,而且只有在同時對多個這樣的字段查詢時才能體現出位圖的優點。

位圖的基本思想就是對每個條件都用0或者1來表示,若有5條記錄,性別分別是男,女,男,男,女,那麼若是使用位圖索引就會創建兩個位圖,對應男的10110和對應女的01001,這樣作有什麼好處呢,就是若是同時對多個這種類型的字段進行and或or查詢時,可使用按位與和按位或來直接獲得結果了。web

爲了進一步榨取MySQL的效率,就要考慮創建組合索引。就是將 name, city, age建到一個索引裏:算法

ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age);

建表時,usernname長度爲 16,這裏用 10。這是由於通常狀況下名字的長度不會超過10,這樣會加速索引查詢速度,還會減小索引文件的大小,提升INSERT的更新速度。spring

若是分別在 usernname,city,age上創建單列索引,讓該表有3個單列索引,查詢時和上述的組合索引效率也會大不同,遠遠低於咱們的組合索引。雖然此時有了三個索引,但MySQL只能用到其中的那個它認爲彷佛是最有效率的單列索引。sql

創建這樣的組合索引,實際上是至關於分別創建了下面三組組合MySQL數據庫索引:數據庫

CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, city VARCHAR(50) NOT NULL, age INT NOT NULL );

usernname,city,age usernname,city usernname 爲何沒有 city,age這樣的組合索引呢?這是由於MySQL組合索引「最左前綴」的結果。簡單的理解就是隻從最左面的開始組合。並非只要包含這三列的查詢都會用到該組合索引,下面的幾個SQL就會用到這個組合MySQL數據庫索引:

SELECT * FROM mytable WHREE username="admin" AND city="鄭州" SELECT * FROM mytable WHREE username="admin"

而下面幾個則不會用到:

SELECT * FROM mytable WHREE age=20 AND city="鄭州" SELECT * FROM mytable WHREE city="鄭州"

使用索引的代價

一、索引須要佔用數據表之外的物理存儲空間
二、建立索引和維護索引要花費必定的時間
三、當對錶進行更新操做時,索引須要被重建,這樣下降了數據的維護速度

什麼狀況下不適合創建索引?

1.對於在查詢過程當中不多使用或參考的列,不該該建立索引。
2.對於那些只有不多數據值的列,不該該建立索引。
3.對於那些定義爲image,text和bit數據類型的列,不該該建立索引。
4.當修改性能遠大於檢索性能,不該該創建索引。


線程池中的corenum和maxnum有什麼不一樣?

(1) 直接提交的隊列:該功能由SynchronizedQueue對象提供。SynchronizedQueue是一個特殊的阻塞隊列。SynchronizedQueue沒有容量,每個插入操做都要等待一個相應的刪除操做,反之每個刪除操做都須要等待對應的插入操做。使用SynchronizedQueue時提交的任務不會被真實的保存,而老是將新任務提交給線程執行,若是沒有空閒的線程則嘗試建立新的線程,若是線程數量達到最大值就執行決絕策略。使用SynchronizedQueue隊列一般要設置很大的maxnumPoolSize,不然很容易執行拒絕策略。能夠當作大小爲0的隊列來理解。

(2) 有界的任務隊列:有界的任務隊列可使用ArrayBlockingQueue實現。當使用有界的任務隊列時,如有新的任務須要執行,若是線程池的實際線程數小於核心線程數,則有優先建立新的線程,若大於核心線程數,則會將新任務加入等待隊列。若隊列已滿,沒法加入則在總線程數不大於最大線程數的前提下,建立新的線程。若大於最大線程數,則執行拒絕策略。也就是說,有界隊列僅當任務隊列滿時纔可能將線程數提高到核心線程數只上,不然確保線程數維持在覈心線程數大小。

(3) 無界任務隊列:無界任務隊列能夠經過LinkedBlockingQueue類來實現。與有界隊列相比,除非系統資源耗盡,不然無界隊列不存在任務入隊失敗的狀況。當有新的任務到來,系統的線程數小於核心線程數時線程池會生成新的線程執行任務,但當系統線程數大於核心線程數後,就不會繼續增長。若後續有新的任務,則將任務放入無界隊列中等待。

(4) 優先任務隊列:優先任務隊列是帶有執行優先級的隊列,經過PriorityBlockingQueue實現,能夠控制任務的執行前後順序,是一個特殊的無界隊列。不管是有界隊列還ArrayBlockingQueue仍是未指定大小的無界隊列LinkedBlockingQueue,都是按照先進先出算法處理任務的,而有限隊列則能夠根據任務自身的優先級順序執行,在確保系統性能的同時,也能有很好的質量保證。

回過頭看Executor框架提供了幾種線程池,newFixedThreadPool()返回的固定大小線程池中核心線程數和最大線程數同樣,而且使用了無界隊列。由於對於固定大小的線程池來講,不存在線程數量的動態變化,因此最大線程數等於核心線程數。同時,使用無界隊列存放沒法當即執行的任務,當任務提交很是頻繁時,隊列可能迅速膨脹,從而耗盡系統資源。

newSingleThreadExecutor()返回的單線程線程池,是固定大小線程池的一種退化,只是簡單的將線程池數量設置爲1。
newCachedThreadExecutor()返回核心線程數爲0,最大線程數爲無窮大的線程池。使用直接提交隊列SynchronizedQueue。
當Executor提供的線程池不知足使用場景時,則須要使用自定義線程池,選擇合適的任務隊列來做爲緩衝。不一樣的併發隊列對系統和性能的影響均不一樣。


如何找出單鏈表中的倒數第k個元素?

思路一:
初看題目,最容易想到的方法就是遍歷。首先遍歷一遍單鏈表,得出整個鏈表的長度n(元素個數從1到n),而後找到倒數第k個元素的位置n-k+1,接着從頭遍歷到第n-k+1元素,就是倒數第k個元素。可是該方法須要對鏈表進行兩次遍歷,遍歷的元素個數爲n+n-k+1=2n+1-k個。

思路二:
有了思路一的提示,是否是能夠想到用兩個指針,讓它們之間的距離保持爲k-1,同時對鏈表進行遍歷,當第一個指針到達鏈表的最後一個元素(即倒數第一個元素時),第二個指針恰好停留在倒數第k個元素上。此方法看似對鏈表進行了一次遍歷,實際上是用兩個指針對鏈表進行了同時遍歷,對鏈表自己而言,它被遍歷的元素個數還是n+n-k+1=2n+1-k個。

思路三:
思路一和思路二是兩種不一樣思路,但就本質而言,都是兩次對鏈表進行2次遍歷,一次遍歷n個元素,另外一次遍歷n-k+1個,總共遍歷2n+1-k個元素。此時,想一想可否再減小遍歷的元素個數而找到倒數第k個元素呢?咱們注意到思路二,是用兩個指針,保持k-1個元素的距離同時進行遍歷的,能否按着每次k個元素這樣的遍歷下去呢。這樣遍歷的結果就是,每次遍歷k個元素,遍歷m次(m=n/k),最後一次遍歷的個數爲i個(i=n%k),咱們只需記錄最後一次遍歷k個元素的起始位置,而後再遍歷i個元素,此時的位置即爲倒數第k個元素。此時,對鏈表遍歷的元素個數爲n+i(i爲n除以k的餘數)。


多線程缺點?

一、將給定的工做量劃分給過多的線程會形成每一個線程的工做量過少,所以可能致使線程啓動和終止時的開銷比程序實際工做的開銷還要多;

二、過多併發線程的存在將致使共享有限硬件資源的開銷增大。

線程相對於進程的優勢:
一、開銷小
二、資源共享性好。

線程相對於進程的缺點:
一、共享資源須要耗費必定的鎖資源,同步相對複雜。
二、一個線程崩潰可能致使整個進程崩潰,這個固然是本身的應用程序有問題


迭代和遞歸的最大區別是?

遞歸與迭代都是基於控制結構:迭代用重複結構,而遞歸用選擇結構。

遞歸與迭代都涉及重複:迭代顯式使用重複結構,而遞歸經過重複函數調用實現重複。

遞歸與迭代都涉及終止測試:迭代在循環條件失敗時終止,遞歸在遇到基本狀況時終止。

使用計數器控制重複的迭代和遞歸都逐漸到達終止點:迭代一直修改計數器,直到計數器值使循環條件失敗;遞歸不斷產生最初問題的簡化副本,直到達到基本狀況。迭代和遞歸過程均可以無限進行:若是循環條件測試永遠不變成false,則迭代發生無限循環;若是遞歸永遠沒法回推到基本狀況,則發生無窮遞歸。
遞歸函數是經過調用函數自身來完成任務,並且在每次調用自身時減小任務量。而迭代是循環的一種形式,這種循環不是由用戶輸入而控制,每次迭代步驟都必須將剩餘的任務減小;也就是說,循環的每一步都必須執行一個有限的過程,並留下較少的步驟。


SQL truncate 、delete與drop區別?

相同點:

1.truncate和不帶where子句的delete、以及drop都會刪除表內的數據。

2.drop、truncate都是DDL語句(數據定義語言),執行後會自動提交。

不一樣點:

  1. truncate 和 delete 只刪除數據不刪除表的結構(定義)

  2. 語句將刪除表的結構被依賴的約束(constrain)、觸發器(trigger)、索引(index);依賴於該表的存儲過程/函數將保留,可是變爲 invalid 狀態。

  1. delete 語句是數據庫操做語言(dml),這個操做會放到 rollback segement 中,事務提交以後才生效;若是有相應的 trigger,執行的時候將被觸發。

truncate、drop 是數據庫定義語言(ddl),操做當即生效,原數據不放到 rollback segment 中,不能回滾,操做不觸發 trigger。

3.delete 語句不影響表所佔用的 extent,高水線(high watermark)保持原位置不動
drop 語句將表所佔用的空間所有釋放。
truncate 語句缺省狀況下見空間釋放到 minextents個 extent,除非使用reuse storage;truncate 會將高水線復位(回到最開始)。

4.速度,通常來講: drop> truncate > delete

5.安全性:當心使用 drop 和 truncate,尤爲沒有備份的時候.不然哭都來不及
使用上,想刪除部分數據行用 delete,注意帶上where子句. 回滾段要足夠大.
想刪除表,固然用 drop;
想保留表而將全部數據刪除,若是和事務無關,用truncate便可。若是和事務有關,或者想觸發trigger,仍是用delete。
若是是整理表內部的碎片,能夠用truncate跟上reuse stroage,再從新導入/插入數據。

6.delete是DML語句,不會自動提交。drop/truncate都是DDL語句,執行後會自動提交。

七、TRUNCATE TABLE 在功能上與不帶 WHERE 子句的 DELETE 語句相同:兩者均刪除表中的所有行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系統和事務日誌資源少。DELETE 語句每次刪除一行,並在事務日誌中爲所刪除的每行記錄一項。TRUNCATE TABLE 經過釋放存儲表數據所用的數據頁來刪除數據,而且只在事務日誌中記錄頁的釋放。

八、TRUNCATE TABLE 刪除表中的全部行,但表結構及其列、約束、索引等保持不變。新行標識所用的計數值重置爲該列的種子。若是想保留標識計數值,請改用 DELETE。若是要刪除表定義及其數據,請使用 DROP TABLE 語句。

九、對於由 FOREIGN KEY 約束引用的表,不能使用 TRUNCATE TABLE,而應使用不帶 WHERE 子句的 DELETE 語句。因爲 TRUNCATE TABLE 不記錄在日誌中,因此它不能激活觸發器。

十、TRUNCATE TABLE 不能用於參與了索引視圖的表。


總結常見的mysql數據庫優化操做?

一、Index索引

二、少用SELECT *

可能有的人查詢數據庫時,遇到要查詢的都會select,這是不恰當的行爲。咱們應該取咱們要用的數據,而不是全取,由於當咱們select時,會增長web服務器的負擔,增長網絡傳輸的負載,查詢速度天然就降低 。

三、開啓查詢緩存

大多數的MySQL服務器都開啓了查詢緩存。這是提升性最有效的方法之一,並且這是被MySQL的數據庫引擎處理的。當有不少相同的查詢被執行了屢次的時候,這些查詢結果會被放到一個緩存中,這樣,後續的相同的查詢就不用操做表而直接訪問緩存結果了。

四、使用NOT NULL

  不少表都包含可爲NULL(空值)的列,即便應用程序並不須要保存 NULL 也是如此 ,這是由於可爲NULL是列的默認屬性。一般狀況下最好指定列爲 NOT NULL,除非真的須要存儲NULL值。若是查詢中包含可爲NULL的列,對 MySQL 來講更難優化 ,由於可爲 NULL 的列使 得索引、索引統計和值比較都更復雜 。可爲NULL 的列會使用更多的存儲空間 ,在MySQL裏也須要特殊處理 。當可爲NULL 的列被索引肘,每一個索引記錄須要一個額 外的字節,在 MyISAM 裏甚至還可能致使固定大小 的索引 (例如只有一個整數列的 索引) 變成可變大小的索引。

  一般把可爲 NULL 的列改成 NOT NULL 帶來的性能提高比較小 ,因此 (調優時) 沒有 必要首先在現有schema中查找井修改掉這種狀況 ,除非肯定這會致使問題。可是, 若是計劃在列上建索引 ,就應該儘可能避免設計成可爲 NULL 的列。固然也有例外 ,例如值得一提的是,InnoDB 使用單獨的位 (bit ) 存儲 NULL 值 ,所 以對於稀疏數據由有很好的空間效率 。但這一點不適用於MyISAM 。

五、避免在 where 子句中使用 or 來鏈接

若是一個字段有索引,一個字段沒有索引,將致使引擎放棄使用索引而進行全表掃描,如:

select id from t where num=10 or Name = 'admin'

能夠這樣查詢:

select id from t where num = 10
union all
select id from t where Name = 'admin'

六、多使用varchar/nvarchar

使用varchar/nvarchar代替 char/nchar ,由於首先變長字段存儲空間小,能夠節省存儲空間,其次對於查詢來講,在一個相對較小的字段內搜索效率顯然要高些。

七、避免大數據量返回

這裏要考慮使用limit,來限制返回的數據量,若是每次返回大量本身不須要的數據,也會下降查詢速度。

八、where子句優化

where 子句中使用參數,會致使全表掃描,由於SQL只有在運行時纔會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然 而,若是在編譯時創建訪問計劃,變量的值仍是未知的,於是沒法做爲索引選擇的輸入項。
應儘可能避免在 where 子句中對字段進行表達式操做,避免在where子句中對字段進行函數操做這將致使引擎放棄使用索引而進行全表掃描。不要在 where 子句中的「=」左邊進行函數、算術運算或其餘表達式運算,不然系統將可能沒法正確使用索引。


SQL語句中executeQuery、executeUpdate、execute的區別?

  1. ResultSet executeQuery(String sql); 執行SQL查詢,並返回ResultSet 對象。

  2. int executeUpdate(String sql); 可執行增,刪,改,返回執行受到影響的行數。

  3. boolean execute(String sql); 可執行任何SQL語句,返回一個布爾值,表示是否返回ResultSet 。

execute是executeQuery和executeUpdate的綜合.

executeUpdate() 這是 PreparedStatement 接口中的方法
executeUpdate(String sql) 這是 PreparedStatement 從父接口 Statement 中繼承過來的方法

executeUpdate() 中執行 SQL 語句須要在建立 PerparedStatement 時經過 Connection 的 prepareStatement(String sql) 方法中寫出,由於 PerparedStatement 中的 SQL 語句數據庫須要進行預編譯和緩存,所以要在建立 PerparedStatement 對象時給出 SQL 語句。

而 executeUpdate(String sql) 是 Statement 中的方法,參數中的 SQL 語句只是提交給數據庫去執行,並不須要預編譯。

<font color=red>若是 SQL 語句中有 ? 佔位符,那麼在設置好佔位符中的值後,必須使用 executeUpdate() 執行。而 executeUpdate(String sql) 只是提交一個 SQL 語句,且這個語句中不能帶有 ? 佔位符。

一、在Java中如何使用execute()、executeQuery()、executeUpdate()三個方法?
execute(String sql)

執行給定的 SQL 語句,該語句可能返回多個結果。

executeQuery(String sql)

執行給定的 SQL 語句,該語句返回單個 ResultSet 對象

executeUpdate(String sql)

執行給定 SQL 語句,該語句可能爲 INSERT、UPDATE 或 DELETE 語句,或者不返回任何內容的 SQL 語句(如 SQL DDL 語句)

頭2種通常在查詢中使用

最後一個在插入、更新、刪除時使用

二、executeQuery()是幹什麼用的?實現什麼功能啊?
使用JDBC鏈接數據庫須要四步,第一步加載驅動程序;第二步,鏈接數據庫;第三步,訪問數據庫;第四步,執行查詢;其中在第四步執行查詢時,要用statement類的executeQuery()方法來下達select指令以查詢數據庫,executeQuery()方法會把數據庫響應的查詢結果存放在ResultSet類對象中供咱們使用。即語句:String sql="select * from"+tableName; ResultSet rs=s.executeQuery(sql);

三、executeQuery、executeUpdate或execute方法區別?
在用純JSP作一個頁面報警功能的時候習慣性的用executeQuery來執行SQL語句,結果執行update時就遇到問題,語句能執行,但返回結果出現問題,另外還忽略了executeUpdate的返回值不是結果集ResultSet,而是數值!特收藏以下一篇文章(感謝網友們對各類信息的貢獻):

JDBCTM中Statement接口提供的execute、executeQuery和executeUpdate之間的區別

Statement 接口提供了三種執行 SQL 語句的方法:executeQuery、executeUpdate 和 execute。使用哪個方法由 SQL 語句所產生的內容決定。

方法executeQuery
用於產生單個結果集的語句,例如 SELECT 語句。 被使用最多的執行 SQL 語句的方法是 executeQuery。這個方法被用來執行 SELECT 語句,它幾乎是使用最多的 SQL 語句。

方法executeUpdate
用於執行 INSERT、UPDATE 或 DELETE 語句以及 SQL DDL(數據定義語言)語句,例如 CREATE TABLE 和 DROP TABLE。INSERT、UPDATE 或 DELETE 語句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一個整數,指示受影響的行數(即更新計數)。對於 CREATE TABLE 或 DROP TABLE 等不操做行的語句,executeUpdate 的返回值總爲零。

使用executeUpdate方法是由於在 createTableCoffees 中的 SQL 語句是 DDL (數據定義語言)語句。建立表,改變表,刪除表都是 DDL 語句的例子,要用 executeUpdate 方法來執行。你也能夠從它的名字裏看出,方法 executeUpdate 也被用於執行更新表 SQL 語句。實際上,相對於建立表來講,executeUpdate 用於更新表的時間更多,由於表只須要建立一次,但常常被更新。

方法execute:
用於執行返回多個結果集、多個更新計數或兩者組合的語句。由於多數程序員不會須要該高級功能

execute方法應該僅在語句能返回多個ResultSet對象、多個更新計數或ResultSet對象與更新計數的組合時使用。當執行某個已存儲過程 或動態執行未知 SQL 字符串(即應用程序程序員在編譯時未知)時,有可能出現多個結果的狀況,儘管這種狀況不多見。
由於方法 execute 處理很是規狀況,因此獲取其結果須要一些特殊處理並不足爲怪。例如,假定已知某個過程返回兩個結果集,則在使用方法 execute 執行該過程後,必須調用方法 getResultSet 得到第一個結果集,而後調用適當的 getXXX 方法獲取其中的值。要得到第二個結果集,須要先調用 getMoreResults 方法,而後再調用 getResultSet 方法。若是已知某個過程返回兩個更新計數,則首先調用方法 getUpdateCount,而後調用 getMoreResults,並再次調用 getUpdateCount。
對於不知道返回內容,則狀況更爲複雜。若是結果是 ResultSet 對象,則方法 execute 返回 true;若是結果是 Java int,則返回 false。若是返回 int,則意味着結果是更新計數或執行的語句是 DDL 命令。在調用方法 execute 以後要作的第一件事情是調用 getResultSet 或 getUpdateCount。調用方法 getResultSet 能夠得到兩個或多個 ResultSet 對象中第一個對象;或調用方法 getUpdateCount 能夠得到兩個或多個更新計數中第一個更新計數的內容。
當 SQL 語句的結果不是結果集時,則方法 getResultSet 將返回 null。這可能意味着結果是一個更新計數或沒有其它結果。在這種狀況下,判斷 null 真正含義的惟一方法是調用方法 getUpdateCount,它將返回一個整數。這個整數爲調用語句所影響的行數;若是爲 -1 則表示結果是結果集或沒有結果。若是方法 getResultSet 已返回 null(表示結果不是 ResultSet 對象),則返回值 -1 表示沒有其它結果。也就是說,當下列條件爲真時表示沒有結果(或沒有其它結果):

((stmt.getResultSet() == null) && (stmt.getUpdateCount() == -1))

若是已經調用方法 getResultSet 並處理了它返回的 ResultSet 對象,則有必要調用方法 getMoreResults 以肯定是否有其它結果集或更新計數。若是 getMoreResults 返回 true,則須要再次調用 getResultSet 來檢索下一個結果集。如上所述,若是 getResultSet 返回 null,則須要調用 getUpdateCount 來檢查 null 是表示結果爲更新計數仍是表示沒有其它結果。

當 getMoreResults 返回 false 時,它表示該 SQL 語句返回一個更新計數或沒有其它結果。所以須要調用方法 getUpdateCount 來檢查它是哪種狀況。在這種狀況下,當下列條件爲真時表示沒有其它結果:

((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))

下面的代碼演示了一種方法用來確認已訪問調用方法 execute 所產生的所有結果集和更新計數:

stmt.execute(queryStringWithUnknownResults);
while (true) {
int rowCount = stmt.getUpdateCount();
if (rowCount > 0) { // 它是更新計數
System.out.println("Rows changed = " + count);
stmt.getMoreResults();


Spring初始化過程?

  在傳統的Java應用中,Bean的生命週期很是簡單。Java的關鍵詞new用來實例化Bean(或許他是非序列化的)。這樣就夠用了。相反,Bean 的生命週期在spring容器中更加細緻。理解Spring Bean的生命週期很是重要,由於你或許要利用Spring提供的機會來訂製Bean的建立過程。

1.容器尋找Bean的定義信息而且將其實例化。

2.使用依賴注入,Spring按照Bean定義信息配置Bean的全部屬性。

3.若是Bean實現了BeanNameAware接口,工廠調用Bean的setBeanName()方法傳遞Bean的ID。

4.若是Bean實現了BeanFactoryAware接口,工廠調用setBeanFactory()方法傳入工廠自身。

5.若是BeanPostProcessor和Bean關聯,那麼它們的postProcessBeforeInitialzation()方法將被調用。

6.若是Bean指定了init-method方法,它將被調用。

7.最後,若是有BeanPsotProcessor和Bean關聯,那麼它們的postProcessAfterInitialization()方法將被調用。

  到這個時候,Bean已經能夠被應用系統使用了,而且將被保留在Bean Factory中知道它再也不須要。有兩種方法能夠把它從Bean Factory中刪除掉。

1.若是Bean實現了DisposableBean接口,destory()方法被調用。

2.若是指定了訂製的銷燬方法,就調用這個方法。

  Bean在Spring應用上下文的生命週期與在Bean工廠中的生命週期只有一點不一樣,惟一不一樣的是,若是Bean實現了ApplicationContextAwre接口,setApplicationContext()方法被調用。


MySQL Hash索引和B-Tree索引的區別?

  MySQL Hash索引結構的特殊性,其檢索效率很是高,索引的檢索能夠一次定位,不像B-Tree 索引須要從根節點到枝節點,最後才能訪問到頁節點這樣屢次的IO訪問,因此 Hash 索引的查詢效率要遠高於 B-Tree 索引。
  可能不少人又有疑問了,既然 Hash 索引的效率要比 B-Tree 高不少,爲何你們不都用 Hash 索引而還要使用 B-Tree 索引呢?任何事物都是有兩面性的,Hash 索引也同樣,雖然 Hash 索引效率高,可是 Hash 索引自己因爲其特殊性也帶來了不少限制和弊端,主要有如下這些。
(1)MySQL Hash索引僅僅能知足"=","IN"和"< >"查詢,不能使用範圍查詢。
因爲 MySQL Hash索引比較的是進行 Hash 運算以後的 Hash 值,因此它只能用於等值的過濾,不能用於基於範圍的過濾,由於通過相應的 Hash 算法處理以後的 Hash 值的大小關係,並不能保證和Hash運算前徹底同樣。
(2)MySQL Hash索引沒法被用來避免數據的排序操做。
因爲 MySQL Hash索引中存放的是通過 Hash 計算以後的 Hash 值,並且Hash值的大小關係並不必定和 Hash 運算前的鍵值徹底同樣,因此數據庫沒法利用索引的數據來避免任何排序運算;
(3)MySQL Hash索引不能利用部分索引鍵查詢。
對於組合索引,Hash 索引在計算 Hash 值的時候是組合索引鍵合併後再一塊兒計算 Hash 值,而不是單獨計算 Hash 值,因此經過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash 索引也沒法被利用。
(4)MySQL Hash索引在任什麼時候候都不能避免表掃描。
前面已經知道,Hash 索引是將索引鍵經過 Hash 運算以後,將 Hash運算結果的 Hash 值和所對應的行指針信息存放於一個 Hash 表中,因爲不一樣索引鍵存在相同 Hash 值,因此即便取知足某個 Hash 鍵值的數據的記錄條數,也沒法從 Hash 索引中直接完成查詢,仍是要經過訪問表中的實際數據進行相應的比較,並獲得相應的結果。
(5)MySQL Hash索引遇到大量Hash值相等的狀況後性能並不必定就會比B-Tree索引高。
對於選擇性比較低的索引鍵,若是建立 Hash 索引,那麼將會存在大量記錄指針信息存於同一個 Hash 值相關聯。這樣要定位某一條記錄時就會很是麻煩,會浪費屢次表數據的訪問,而形成總體性能低下。


單例與靜態變量的區別

單例的特色:

一、保證某類只存在惟一實例。
二、該類自己完成自身的初始化。
三、獲取該惟一實例的方式很是明確,能夠經過該類自己定義的靜態方法getInstance()獲取該類的惟一實例引用。

靜態變量定義某類的實例引用特色
一、該類的實例引用的靜態變量可定義在任何文檔類當中。
二、獲取該類的實例引用的靜態變量,能夠經過定義該靜態變量的類名經過點語法進行訪問該引用。
三、任何位置能夠對該靜態變量進行從新賦值。

  經過這二者方式的特色,咱們能夠很明顯的看出二者之間的區別。(這一切都是基於某類只須要存在一個實例對象的前提來討論)
首先靜態變量方式不能確保某類的實例的惟一性,這樣在項目中,可能由於在某個文檔類中對該靜態變量進行再次賦值,存不可意料的風險(這種風險能夠規避)。一樣的,由於靜態變量的定義的位置不肯定,因此須要協議商定,這些靜態變量分類別進行定義在一個固定的位置(好比說某個專門存放靜態變量方式的某類的對象的引用的文檔類當中)。
  而單例模式也就是靜態變量方式建立一個類的實例引用所帶來的缺陷的改善。首先解決引用的惟一實例可能被從新賦值的問題,單例模式中的getInstance()靜態方法實現時,採用懶漢式建立一個對象(固然這只是建立方式的一種),規避了這一風險,無則建立,有則跳過建立。其次,getInstance()靜態方法定義在該類的內部,獲取該類對象的引用位置很是明確,無需額外的溝通商定,團隊成員拿起即用。最後一個區別並非很明顯,聲明一個靜態變量,實際上,咱們會直接對其進行初始化賦值,這樣,在內存佔用上,所佔用的內存爲該初始化賦值對象實際的內存。而單例模式能夠經過懶漢建立法延遲該內存的佔用,要知道,當一個靜態變量只進行聲明,而不進行初始化時,實際的內存佔用只有4個字節(筆者我的推測,這四個字節只是一個指針地址所佔用的內存空間)。


關於HashMap與HashTable

<font color=red>HashMap/HashTable初始容量大小和每次擴充容量大小的不一樣</font>

能夠看到HashTable默認的初始大小爲11,以後每次擴充爲原來的2n+1。HashMap默認的初始化大小爲16,以後每次擴充爲原來的2倍。還有我沒列出代碼的一點,就是若是在建立時給定了初始化大小,那麼HashTable會直接使用你給定的大小,而HashMap會將其擴充爲2的冪次方大小。

也就是說HashTable會盡可能使用素數、奇數。而HashMap則老是使用2的冪做爲哈希表的大小。咱們知道當哈希表的大小爲素數時,簡單的取模哈希的結果會更加均勻(具體證實,見這篇文章),因此單從這一點上看,HashTable的哈希表大小選擇,彷佛更高明些。但另外一方面咱們又知道,在取模計算時,若是模數是2的冪,那麼咱們能夠直接使用位運算來獲得結果,效率要大大高於作除法。因此從hash計算的效率上,又是HashMap更勝一籌。

因此,事實就是HashMap爲了加快hash的速度,將哈希表的大小固定爲了2的冪。固然這引入了哈希分佈不均勻的問題,因此HashMap爲解決這問題,又對hash算法作了一些改動。具體咱們來看看,在獲取了key對象的hashCode以後,HashTable和HashMap分別是怎樣將他們hash到肯定的哈希桶(Entry數組位置)中的。

正如咱們所言,HashMap因爲使用了2的冪次方,因此在取模運算時不須要作除法,只須要位的與運算就能夠了。可是因爲引入的hash衝突加重問題,HashMap在調用了對象的hashCode方法以後,又作了一些位運算在打散數據。關於這些位計算爲何能夠打散數據的問題,本文再也不展開了。感興趣的能夠看這裏。

<font color=red>HashMap是支持null鍵和null值的,而HashTable在遇到null時,會拋出NullPointerException異常。</font>

這並非由於HashTable有什麼特殊的實現層面的緣由致使不能支持null鍵和null值,這僅僅是由於HashMap在實現時對null作了特殊處理,將null的hashCode值定爲了0,從而將其存放在哈希表的第0個bucket中。


JSP指令元素與動做元素的區別

1:<jsp:include page="top.jsp">先將top.jsp中的java腳本和jsp指令都執行完畢之後再將top.jsp頁面加入到引用頁面中。

2:<%@ include file="top.jsp"%>靜態讀取:則是將top.jsp的整個頁面不加解析(不管是腳本仍是指令)通通讀入到引用頁面中,而後和引用頁面一塊兒進行解析(即開始執行腳本和指令)。

3:區別:其實上邊的兩條就是區別,可是須要注意的是用<%@ include file=""%>的時候被引用頁面中不能再出現其餘網頁標籤和page指令了,不然會衝突的

(jsp:include page="")

父頁面和包含進來的頁面單獨編譯,單獨翻譯成servlet後,在前臺拼成一個HTML頁面。

(%@include file=""%)

父頁面和包含進來的頁面,代碼合併後,才一塊兒翻譯成servlet,反饋到前臺,造成一個HTML頁面。

由此咱們知道:jsp頁面是把include指令元素(<%@ include file=""%>)所指定的頁面的實際內容(也就是代碼段)加入到引入它的jsp頁面中,合成一個文件後被jsp容器將它轉化成servlet。能夠看到這時會產生一個臨時class文件和一個servlet源文件。而動做元素(<jsp:include page=""/>)是在請求處理階段引入的,會被JSP容器生成兩個臨時class文件和兩個servlet原文件。而引入的只是servlet的輸出結果,即JspWriter對象的輸出結果,而不是jsp的源代碼。

java是在服務器端運行的代碼,jsp在服務器的servlet裏運行,而javascript和html都是在瀏覽器端運行的代碼。因此加載執行順序是是java>jsp>js。

全部的JSP都會在客戶端發出請求後被容器轉譯成servlet的源代碼(java),而後再將源碼(java)編譯成servlet的類(class),放入到內存裏面。


可重入鎖 公平鎖 讀寫鎖

1.可重入鎖

若是鎖具有可重入性,則稱做爲可重入鎖。

像Synchronized和ReentrantLock都是可重入鎖,可重入性在我看來實際上代表了鎖的分配機制:

基於線程的分配,而不是基於方法調用的分配。

舉個簡單的例子,當一個線程執行到某個Synchronized方法時,好比說method1,而在method1中會調用另一個Synchronized方法method2,此時線程沒必要從新去申請鎖,而是能夠直接執行方法method2。

class MyClass {
    public synchronized void method1() {
        method2();
    }
     
    public synchronized void method2() {
         
    }
}

上述代碼中的兩個方法method1和method2都用Synchronized修飾了。

假如某一時刻,線程A執行到了method1,此時線程A獲取了這個對象的鎖,而因爲method2也是Synchronized方法,假如Synchronized不具有可重入性,此時線程A須要從新申請鎖。

可是這就會形成一個問題,由於線程A已經持有了該對象的鎖,而又在申請獲取該對象的鎖,這樣就會線程A一直等待永遠不會獲取到的鎖。

而因爲Synchronized和Lock都具有可重入性,因此不會發生上述現象。

2.可中斷鎖

可中斷鎖:顧名思義,就是能夠響應中斷的鎖。

在Java中,Synchronized就不是可中斷鎖,而Lock是可中斷鎖。

若是某一線程A正在執行鎖中的代碼,另外一線程B正在等待獲取該鎖,可能因爲等待時間過長,線程B不想等待了,想先處理其餘事情,咱們可讓它中斷本身或者在別的線程中中斷它,這種就是可中斷鎖。

在前面演示LockInterruptibly()的用法時已經體現了Lock的可中斷性。

3.公平鎖

公平鎖即儘可能以請求鎖的順序來獲取鎖。好比同是有多個線程在等待一個鎖,當這個鎖被釋放時,等待時間最久的線程(最早請求的線程)會得到該所,這種就是公平鎖。

非公平鎖即沒法保證鎖的獲取是按照請求鎖的順序進行的。這樣就可能致使某個或者一些線程永遠獲取不到鎖。

在Java中,Synchronized就是非公平鎖,它沒法保證等待的線程獲取鎖的順序。

而對於ReentrantLock和ReentrantReadWriteLock,它默認狀況下是非公平鎖,可是能夠設置爲公平鎖。這一點由構造函數可知:

public ReentrantLock() {
        sync = new NonfairSync();
    }


    public ReentrantLock(boolean fair) {
        sync = (fair)? new FairSync() : new NonfairSync();
    }

在ReentrantLock中定義了2個靜態內部類,一個是NotFairSync,一個是FairSync,分別用來實現非公平鎖和公平鎖。

咱們能夠在建立ReentrantLock對象時,經過知道布爾參數來決定使用非公平鎖仍是公平鎖。

若是參數爲true表示爲公平鎖,爲fasle爲非公平鎖。默認狀況下,若是使用無參構造器,則是非公平鎖。

另外在ReentrantLock類中定義了不少方法,好比:

isFair() //判斷鎖是不是公平鎖
isLocked() //判斷鎖是否被任何線程獲取了
isHeldByCurrentThread() //判斷鎖是否被當前線程獲取了
hasQueuedThreads() //判斷是否有線程在等待該鎖

在ReentrantReadWriteLock中也有相似的方法,一樣也能夠設置爲公平鎖和非公平鎖。

不過要記住,ReentrantReadWriteLock並未實現Lock接口,它實現的是ReadWriteLock接口。

4.讀寫鎖

讀寫鎖將對一個資源(好比文件)的訪問分紅了2個鎖,一個讀鎖和一個寫鎖。

正由於有了讀寫鎖,才使得多個線程之間的讀操做不會發生衝突。

ReadWriteLock就是讀寫鎖,它是一個接口,ReentrantReadWriteLock實現了這個接口。

能夠經過readLock()獲取讀鎖,經過writeLock()獲取寫鎖。


數據庫的樂觀鎖與悲觀鎖

樂觀鎖是假定讀取的數據,在寫以前不會被更新。適用於數據更新不頻繁的場景。

相反,當數據更新頻繁的時候,樂觀鎖的效率很低,由於基本上每次寫的時候都要重複讀寫兩次以上。

  1. 對於數據更新頻繁的場合,悲觀鎖效率更高 ;

  2. 對於數據更新不頻繁的場合,樂觀鎖效率更高;

通常來講若是併發量很高的話,建議使用悲觀鎖,不然的話就使用樂觀鎖。

若是併發量很高時使用樂觀鎖的話,會致使不少的併發事務回滾、操做失敗。


工做內存與主內存

線程工做內存是cpu寄存器和高速緩存的抽象描述,使用頻率高的數據從主存拷貝到高速緩存中,每一個線程在cpu高速緩存中對拷貝的數據進行讀取、計算、賦值,再在合適的時候同步更新到主存的該數據,如i=1,i+1=2,若2在更新到主存前,其餘線程是不知道該值被改變了,其餘線程高速緩存中該值依然爲1。

解決方法:須要各線程間可見的變量前加上volatile修飾,在一個線程的高速緩存中改變該值時,其餘線程會得到該值的更新值。


垃圾回收器

垃圾收集器:

串行:Serial、Parallel、CMS

CMS:每一個垃圾收集週期只有兩次短的停頓,開始時有一個短的停頓,稱爲初始標記;標記從外部直接可達的老年代對象;而後在併發標記階段,標記全部從這些對象可達的存活對象;因爲在標記期間應用可能正在運行並更新引用,因此到併發標記階段結束時,未必全部存活的對象都能確保被標記;因此必須再次停頓,稱爲從新標記;最後一個階段是併發清除


c3p0與dbcp區別

dbcp沒有自動地去回收空閒鏈接的功能 c3p0有自動回收空閒鏈接功能 。

二者主要是對數據鏈接的處理方式不一樣!c3p0提供最大空閒時間,dbcp提供最大鏈接數。

前者當鏈接超過最大空閒鏈接時間時,當前鏈接就會被斷掉。dbcp當鏈接數超過最大鏈接數時,全部鏈接都會被斷開。

dbcp和c3p0都是單線程的,在高併發的環境下性能會很是低下;tomcat jdbc pool 近乎兼容 dbcp ,性能更高,異步方式獲取鏈接。

相關文章
相關標籤/搜索