




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、1 基礎篇1.1 基本功1.1.1 面向對象特征封裝,繼承,多態和抽象1、 封裝封裝給對象提供了隱藏內部特性和行為的能力。對象提供一些能被其他對象訪問的方法來改變它內部的數據。在 Java 當中,有 3 種修飾符: public, private 和 protected。每一種修飾符給其他的位于同一個包或者不同包下面對象賦予了不同的訪問權限。下面列出了使用封裝的一些好處:1) 通過隱藏對象的屬性來保護對象內部的狀態。2) 提高了代碼的可用性和可維護性,因為對象的行為可以被單獨的改變或者是擴展。3) 禁止對象之間的不良交互提高模塊化2、 繼承繼承給對象提供了從基類獲取字段和方法的能力。繼承提供了
2、代碼的重用行,也可以在不修改類的情況下給現存的類添加新特性。3、 多態多態是編程語言給不同的底層數據類型做相同的接口展示的一種能力。一個多態類型上的操作可以應用到其他類型的值上面。4、 抽象抽象是把想法從具體的實例中分離出來的步驟,因此,要根據他們的功能而不是實現細節來創建類。 Java 支持創建只暴漏接口而不包含方法實現的抽象的類。這種抽象技術的主要目的是把類的行為和實現細節分離開。1.1.2 final, finally, finalize 的區別1、 final修飾符(關鍵字)如果一個類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承。因此一個類不能既被聲明為 abs
3、tract的,又被聲明為final的。將變量或方法聲明為final,可以保證它們在使用中不被改變。被聲明為final的變量必須在聲明時給定初值,而在以后的引用中只能讀取,不可修改。被聲明為final的方法也同樣只能使用,不能重載。2、 finally在異常處理時提供 finally 塊來執行任何清除操作。如果拋出一個異常,那么相匹配的 catch 子句就會執行,然后控制就會進入 finally 塊(如果有的話)。3、 finalize方法名。Java 技術允許使用 finalize() 方法在垃圾收集器將對象從內存中清除出去之前做必要的清理工作。這個方法是由垃圾收集器在確定這個對象沒有被引用時
4、對這個對象調用的。它是在 Object 類中定義的,因此所有的類都繼承了它。子類覆蓋 finalize() 方法以整理系統資源或者執行其他清理工作。finalize() 方法是在垃圾收集器刪除對象之前對這個對象調用的。1.1.3 int 和 Integer 有什么區別int是基本數據類型 ,而Integer是其包裝類,注意是一個類。 為什么要提供包裝類呢? 一是為了在各種類型間轉化,通過各種方法的調用。否則你無法直接通過變量轉化。1.1.4 重載和重寫的區別override(重寫) 1. 方法名、參數、返回值相同。 2. 子類方法不能縮小父類方法的訪問權限。 3.
5、 子類方法不能拋出比父類方法更多的異常(但子類方法可以不拋出異常)。 4. 存在于父類和子類之間。 5. 方法被定義為final不能被重寫。overload(重載)1. 參數類型、個數、順序至少有一個不相同。2. 不能重載只有返回值不同的方法名。3. 存在于父類和子類、同類中。區別點重載重寫(覆寫)英文OverloadingOveriding定義方法名稱相同,參數的類型或個數不同方法名稱、參數類型、返回值類型全部相同權限對權限沒要求被重寫的方法不能擁有更嚴格的權限范圍發生在一個類中發生在繼承類中1.1.5 抽象類和接口有什么區別接口是公開的,里面不能有私有的方法或變量,是用于讓別人使用的,而抽
6、象類是可以有私有方法或私有變量的,另外,實現接口的一定要實現接口里定義的所有方法,而實現抽象類可以有選擇地重寫需要用到的方法,一般的應用里,最頂級的是接口,然后是抽象類實現接口,最后才到具體類實現。 還有,接口可以實現多重繼承,而一個類只能繼承一個超類,但可以通過繼承多個接口實現多重繼承,接口還有標識(里面沒有任何方法,如Remote接口)和數據共享(里面的變量全是常量)的作用。1.1.6 說說反射的用途及實現Java反射機制主要提供了以下功能:在運行時構造一個類的對象;判斷一個類所具有的成員變量和方法;調用一個對象的方法;生成動態代理。反射最大的應用就是框架Java反射的主要功能:
7、 - 確定一個對象的類 - 取出類的modifiers,數據成員,方法,構造器,和超類. - 找出某個接口里定義的常量和方法說明. - 創建一個類實例,這個實例在運行時刻才有名字(運行時間才生成的對象). - 取得和設定對象數據成員的值,如果數據成員名是運行時刻確定的也能做到. - 在運行時刻調用動態對象的方法. - 創建數組,數組大小和類型在運行時刻才確定,也能更改數組成員的值.反射的應用很多,很多框架都有用到spring 的 ioc/di 也是反射. javaBean和jsp之間調用也是反射. str
8、uts的 FormBean 和頁面之間也是通過反射調用. JDBC 的 classForName()也是反射. hibernate的 find(Class clazz) 也是反射.反射還有一個不得不說的問題,就是性能問題,大量使用反射系統性能大打折扣。怎么使用使你的系統達到最優就看你系統架構和綜合使用問題啦,這里就不多說了。來源:1.1.7 說說自定義注解的場景及實現登陸、權限攔截、日志處理,以及各種Java框架,如Spring,Hibernate,JUnit 提到注解就不能不說反射,Java自定義注解是通過運行時靠反射獲取注解。實際開發中,例如我們要獲取某個方法的調用日志
9、,可以通過AOP(動態代理機制)給方法添加切面,通過反射來獲取方法包含的注解,如果包含日志注解,就進行日志記錄。1.1.8 HTTP 請求的 GET 與 POST 方式的區別1、 請求數據的方式GET請求,請求的數據會附加在URL之后,以?分割URL和傳輸數據,多個參數用&連接。URL的編碼格式采用的是ASCII編碼,而不是uniclde,即是說所有的非ASCII字符都要編碼之后再傳輸。POST請求會把請求的數據放置在HTTP請求包的包體中。因此,GET請求的數據會暴露在地址欄中,而POST請求則不會。2、 傳輸數據的大小 在HTTP規范中,沒有對URL的長度和傳輸的數據大小進行限制。
10、但是在實際開發過程中,對于GET,特定的瀏覽器和服務器對URL的長度有限制。因此,在使用GET請求時,傳輸數據會受到URL長度的限制。 對于POST,由于不是URL傳值,理論上是不會受限制的,但是實際上各個服務器會規定對POST提交數據大小進行限制,Apache、IIS都有各自的配置。 3、 安全性 POST的安全性比GET的高。這里的安全是指真正的安全,而不同于上面GET提到的安全方法中的安全,上面提到的安全僅僅是不修改服務器的數據。比如,在進行登錄操作,通過GET請求,用戶名和密碼都會暴露再URL上,因為登錄頁面有可能被瀏覽器緩存以及其他人查看瀏覽器的歷史記錄的原因,此時的用戶名和密碼就很
11、容易被他人拿到了。除此之外,GET請求提交的數據還可能會造成Cross-site request frogery攻擊 4、HTTP中的GET,POST,SOAP協議都是在HTTP上運行的參考:1.1.9 Session與Cookie 區別cookie是Web服務器發送給瀏覽器的一塊信息。瀏覽器會在本地文件中給每一個 Web 服務器存儲cookie。以后瀏覽器在給特定的 Web 服務器發請求的時候,同時會發送所有為該服務器存儲的 cookie。下面列出了session和cookie的區別:無論客戶端瀏覽器做怎么樣的設置,session都應該能正常工作。客戶端可以選擇禁用cookie,但是,ses
12、sion 仍然是能夠工作的,因為客戶端無法禁用服務端的session。1.1.10 JDBC 流程1、 加載JDBC驅動程序: 在連接數據庫之前,首先要加載想要連接的數據庫的驅動到JVM(Java虛擬機),這通過java.lang.Class類的靜態方法forName(String className)實現。例如:/加載MySql的驅動類Class.forName("com.mysql.jdbc.Driver");成功加載后,會將Driver類的實例注冊到DriverManager類中。2、 提供JDBC連接的URL- 連接URL定義了連接數據庫時的協議、子協議、
13、數據源標識。- 書寫形式:協議:子協議:數據源標識協議:在JDBC中總是以jdbc開始 子協議:是橋連接的驅動程序或是數據庫管理系統名稱。數據源標識:標記找到數據庫來源的地址與連接端口。例如:/MySql的連接URL,true表示使用Unicode字符集, characterEncoding字符編碼方式。jdbc:mysql:/localhost:3306/test?useUnicode=true&characterEncoding=gbk;3、創建數據庫的連接 - 要連接數據庫,需要向java.sql.DriverManager請求并獲得Connection對象, 該對象就
14、代表一個數據庫的連接。 - 使用DriverManager的getConnectin(String url , String username , String password )方法傳入指定的欲連接的數據庫的路徑、數據庫的用戶名和 密碼來獲得。例如: /連接MySql數據庫,用戶名和密碼都是rootString url = "jdbc:mysql:/localhost:3306/test"Connection con = DriverManager.getConnection(url, "r
15、oot","root")4、 創建一個Statement,要執行SQL語句,必須獲得java.sql.Statement實例,Statement實例分為以下3 種類型:1) 執行靜態SQL語句。通常通過Statement實例實現。Statement stmt = con.createStatement() ;2) 執行動態SQL語句。通常通過PreparedStatement實例實現。PreparedStatement pstmt = con.prepareStatement(sql) ; 3) 執行數據庫存儲過程。通常通過CallableStatement實例實
16、現。 CallableStatement cstmt = con.prepareCall(“CALL demoSp(? , ?)”) ; 5、 執行SQL語句提供了三種執行SQL語句的方法:executeQuery 、executeUpdate 和execute1) ResultSet executeQuery(String sqlString):執行查詢數據庫的SQL語句 ,返回一個結果集(ResultSet)對象。2) int executeUpdate(String sqlString):用于執行INSERT、UPDATE或 DELETE語句以及SQL DDL語句,如
17、:CREATE TABLE和DROP TABLE等3) execute(sqlString):用于執行返回多個結果集、多個更新計數或二者組合的 語句。 6、 處理結果:1) 執行更新返回的是本次操作影響到的記錄數。2) 執行查詢返回的結果是一個ResultSet對象。 ResultSet包含符合SQL語句中條件的所有行,并且它通過一套get方法提供了對這些行中數據的訪問(列是從左到右編號的,并且從列1開始)。 使用結果集(ResultSet)對象的訪問方法獲取數據: while(rs.next() String name = rs.getStrin
18、g(“name”) ; String pass = rs.getString(1) ; / 此方法比較高效 7、 關閉JDBC對象操作完成以后要把所有使用的JDBC對象全都關閉,以釋放JDBC資源,關閉順序和聲明順序相反:1) 關閉記錄集rs.close()2) 關閉聲明stmt.close()3) 關閉連接對象conn.close()1.1.11 MVC 設計思想M:Model 模型 V:View 視圖 C:Controller 控制器 模型就是封裝業務邏輯和數據的一個一個的模塊,控制器就是調用這些模塊的(java中通常是用Servlet來
19、實現,框架的話很多是用Struts2來實現這一層),視圖就主要是你看到的,比如JSP等。當用戶發出請求的時候,控制器根據請求來選擇要處理的業務邏輯和要選擇的數據,再返回去把結果輸出到視圖層,這里可能是進行重定向或轉發等.1.1.12 equals 與 = 的區別值類型(int,char,long,boolean等)都是用=判斷相等性。對象引用的話,=判斷引用所指的對象是否是同一個。equals是Object的成員函數,有些類會覆蓋(override)這個方法,用于判斷對象的等價性。例如String類,兩個引用所指向的String都是”abc”,但可能出現他們實際對應的對象并不是同一個(和jvm
20、實現方式有關),因此用=判斷他們可能不相等,但用equals判斷一定是相等的。1.2 集合1.2.1 List 和 Set 區別List,Set都是繼承自Collection接口List特點:元素有放入順序,元素可重復Set特點:元素無放入順序,元素不可重復,重復元素會覆蓋掉(注意:元素雖然無放入順序,但是元素在set中的位置是有該元素的HashCode決定的,其位置其實是固定的,加入Set的Object必須定義equals()方法,另外list支持for循環,也就是通過下標來遍歷,也可以用迭代器,但是set只能用迭代,因為他無序,無法用下標來取得想要的值。)Set和List對比:Set:檢索
21、元素效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變。List:和數組類似,List可以動態增長,查找元素效率高,插入刪除元素效率低,因為會引起其他元素位置改變。1.2.2 List 和 Map 區別List是對象集合,允許對象重復。Map是鍵值對的集合,不允許key重復。1.2.3 Arraylist 與 LinkedList 區別Arraylist:優點:ArrayList是實現了基于動態數組的數據結構,因為地址連續,一旦數據存儲好了,查詢操作效率會比較高(在內存里是連著放的)。缺點:因為地址連續, ArrayList要移動數據,所以插入和刪除操作效率比較低。LinkedList
22、:優點:LinkedList基于鏈表的數據結構,地址是任意的,所以在開辟內存空間的時候不需要等一個連續的地址,對于新增和刪除操作add和remove,LinedList比較占優勢。LinkedList 適用于要頭尾操作或插入指定位置的場景缺點:因為LinkedList要移動指針,所以查詢操作性能比較低。適用場景分析:當需要對數據進行對此訪問的情況下選用ArrayList,當需要對數據進行多次增加刪除修改時采用LinkedList。1.2.4 ArrayList 與 Vector 區別/構造一個初始容量為10的空列表public ArrayList()/構造一個具有指定初始容量的空列表
23、。public ArrayList(int initialCapacity)/構造一個包含指定 collection 的元素的列表public ArrayList(Collection<? extends E> c)Vector有四個構造方法:/使用指定的初始容量和等于零的容量增量構造一個空向量public Vector()/構造一個空向量,使其內部數據數組的大小,其標準容量增量為零public Vector(int initialCapacity)/構造一個包
24、含指定 collection 中的元素的向量public Vector(Collection<? extends E> c) /使用指定的初始容量和容量增量構造一個空的向量public Vector(int initialCapacity,int capacityIncrement) ArrayList和Vector都是用數組實現的,主要有這么三個區別:Vector是多線程安全的,線程安全就是說多線程訪問同一代碼,不會產生不確定的結果。而ArrayList不是,這個可以從源碼中看出,Vecto
25、r類中的方法很多有synchronized進行修飾,這樣就導致了Vector在效率上無法與ArrayList相比;兩個都是采用的線性連續空間存儲元素,但是當空間不足的時候,兩個類的增加方式是不同。Vector可以設置增長因子,而ArrayList不可以。Vector是一種老的動態數組,是線程同步的,效率很低,一般不贊成使用。適用場景分析:Vector是線程同步的,所以它也是線程安全的,而ArrayList是線程異步的,是不安全的。如果不考慮到線程的安全因素,一般用ArrayList效率比較高。如果集合中的元素的數目大于目前集合數組的長度時,在集合中使用數據量比較大的數據,用Vector有一定的
26、優勢。1.2.5 HashMap和Hashtable的區別1.hashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()方法。2.hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。3.hashMap允許空鍵值,而hashTable不允許。注意: TreeMap:非線程安全基于紅黑樹實現。TreeMap沒有調優選項,因為該樹總處于平衡狀態。Treemap:適用于按自然順序或自定義順序遍歷鍵(key)。參考:1.2.6 HashSet 和 HashMap 區別set是線性結構,se
27、t中的值不能重復,hashset是set的hash實現,hashset中值不能重復是用hashmap的key來實現的。map是鍵值對映射,可以空鍵空值。HashMap是Map接口的hash實現,key的唯一性是通過key值hash值的唯一來確定,value值是則是鏈表結構。他們的共同點都是hash算法實現的唯一性,他們都不能持有基本類型,只能持有對象1.2.7 HashMap 和 ConcurrentHashMap 的區別ConcurrentHashMap是線程安全的HashMap的實現。(1)ConcurrentHashMap對整個桶數組進行了分割分段(Segment),然后在每一個分段上都
28、用lock鎖進行保護,相對于HashTable的syn關鍵字鎖的粒度更精細了一些,并發性能更好,而HashMap沒有鎖機制,不是線程安全的。(2)HashMap的鍵值對允許有null,但是ConCurrentHashMap都不允許。1.2.8 HashMap 的工作原理及代碼實現簡單地說,HashMap 在底層將 key-value 當成一個整體進行處理,這個整體就是一個 Entry 對象。HashMap 底層采用一個 Entry 數組來保存所有的 key-value 對,當需要存儲一個 Entry 對象時,會根據hash算法來決定其在數組中的存儲位置,在根據equals方法決定其在該數組位置
29、上的鏈表中的存儲位置;當需要取出一個Entry時,也會根據hash算法找到其在數組中的存儲位置,再根據equals方法從該位置上的鏈表中取出該Entry。Fail-Fast機制是java集合(Collection)中的一種錯誤機制。當多個線程對同一個集合的內容進行操作時,就可能會產生 fail-fast 事件。例如:當某一個線程A通過 iterator去遍歷某集合的過程中,若該集合的內容被其他線程所改變了;那么線程A訪問集合時,就會拋出 ConcurrentModificationException異常,產生 fail-fast 事件。參考:ihui.github.io/2015/07/01/
30、Java集合學習1:HashMap的實現原理1.2.9 ConcurrentHashMap 的工作原理及代碼實現HashTable里使用的是synchronized關鍵字,這其實是對對象加鎖,鎖住的都是對象整體,當Hashtable的大小增加到一定的時候,性能會急劇下降,因為迭代時需要被鎖定很長的時間。ConcurrentHashMap算是對上述問題的優化,其構造函數如下,默認傳入的是16,0.75,16。ConcurrentHashMap引入了分割(Segment),上面代碼中的最后一行其實就可以理解為把一個大的Map拆分成N個小的HashTable,在put方法中,會根據hash(para
31、mK.hashCode()來決定具體存放進哪個Segment,如果查看Segment的put操作,我們會發現內部使用的同步機制是基于lock操作的,這樣就可以對Map的一部分(Segment)進行上鎖,這樣影響的只是將要放入同一個Segment的元素的put操作,保證同步的時候,鎖住的不是整個Map(HashTable就是這么做的),相對于HashTable提高了多線程環境下的性能,因此HashTable已經被淘汰了。1.3 線程1.3.1 創建線程的方式及實現Java中創建線程主要有三種方式:一、繼承Thread類創建線程類(1)定義Thread類的子類,并重寫該類的run方法,該run方法
32、的方法體就代表了線程要完成的任務。因此把run()方法稱為執行體。(2)創建Thread子類的實例,即創建了線程對象。(3)調用線程對象的start()方法來啟動該線程。二、通過Runnable接口創建線程類(1)定義runnable接口的實現類,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執行體。(2)創建 Runnable實現類的實例,并依此實例作為Thread的target來創建Thread對象,該Thread對象才是真正的線程對象。(3)調用線程對象的start()方法來啟動該線程。三、通過Callable和Future創建線程(1)創建Callable接口
33、的實現類,并實現call()方法,該call()方法將作為線程執行體,并且有返回值。(2)創建Callable實現類的實例,使用FutureTask類來包裝Callable對象,該FutureTask對象封裝了該Callable對象的call()方法的返回值。(3)使用FutureTask對象作為Thread對象的target創建并啟動新線程。(4)調用FutureTask對象的get()方法來獲得子線程執行結束后的返回值創建線程的三種方式的對比采用實現Runnable、Callable接口的方式創見多線程時,優勢是:線程類只是實現了Runnable接口或Callable接口,還可以繼承其他類
34、。在這種方式下,多個線程可以共享同一個target對象,所以非常適合多個相同線程來處理同一份資源的情況,從而可以將CPU、代碼和數據分開,形成清晰的模型,較好地體現了面向對象的思想。劣勢是:編程稍微復雜,如果要訪問當前線程,則必須使用Thread.currentThread()方法。使用繼承Thread類的方式創建多線程時優勢是:編寫簡單,如果需要訪問當前線程,則無需使用Thread.currentThread()方法,直接使用this即可獲得當前線程。劣勢是:線程類已經繼承了Thread類,所以不能再繼承其他父類。1.3.2 sleep() 、join()、yield()有什么區別1、sle
35、ep()方法在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行),此操作受到系統計時器和調度程序精度和準確性的影響。讓其他線程有機會繼續執行,但它并不釋放對象鎖。也就是如果有Synchronized同步塊,其他線程仍然不能訪問共享數據。注意該方法要捕獲異常比如有兩個線程同時執行(沒有Synchronized),一個線程優先級為MAX_PRIORITY,另一個為MIN_PRIORITY,如果沒有Sleep()方法,只有高優先級的線程執行完成后,低優先級的線程才能執行;但當高優先級的線程sleep(5000)后,低優先級就有機會執行了。 總之,sleep()可以使低優先級的線程得到執行的
36、機會,當然也可以讓同優先級、高優先級的線程有執行的機會。2、yield()方法yield()方法和sleep()方法類似,也不會釋放“鎖標志”,區別在于,它沒有參數,即yield()方法只是使當前線程重新回到可執行狀態,所以執行yield()的線程有可能在進入到可執行狀態后馬上又被執行,另外yield()方法只能使同優先級或者高優先級的線程得到執行機會,這也和sleep()方法不同。3、join()方法Thread的非靜態方法join()讓一個線程B“加入”到另外一個線程A的尾部。在A執行完畢之前,B不能工作。Thread t = new MyThread(); t.start();
37、 t.join(); 保證當前線程停止執行,直到該線程所加入的線程完成為止。然而,如果它加入的線程沒有存活,則當前線程不需要停止。1.3.3 說說 CountDownLatch 原理CountDownLatch是同步工具類之一,可以指定一個計數值,在并發環境下由線程進行減1操作,當計數值變為0之后,被await方法阻塞的線程將會喚醒,實現線程間的同步。1、構造器。構造函數很簡單地傳遞計數值給Sync,并且設置了state。2、 阻塞線程。await方法,直接調用了AQS(即Sync)的acquireSharedInterruptibly首先嘗試獲取共享鎖,實現方式和獨占鎖類
38、似,由CountDownLatch實現判斷邏輯。返回1代表獲取成功,返回-1代表獲取失敗。如果獲取失敗,需要調用doAcquireSharedInterruptibly:doAcquireSharedInterruptibly的邏輯和獨占功能具體如下:1) 創建的Node是定義成共享的(Node.SHARED);2) 被喚醒后重新嘗試獲取鎖,不只設置自己為head,還需要通知其他等待的線程。(重點看后文釋放操作里的setHeadAndPropagate)3、 釋放操作。countDown操作實際就是釋放鎖的操作,每調用一次,計數值減少1。同樣是首先嘗試釋放鎖,具體實現在CountDownLat
39、ch中:死循環加上cas的方式保證state的減1操作,當計數值等于0,代表所有子線程都執行完畢,被await阻塞的線程可以喚醒了,下一步調用doReleaseShared:標記1里,頭節點狀態如果SIGNAL,則狀態重置為0,并調用unparkSuccessor喚醒下個節點。標記2里,被喚醒的節點狀態會重置成0,在下一次循環中被設置成PROPAGATE狀態,代表狀態要向后傳播。參考:分析CountDownLatch的實現原理什么時候使用CountDownLatchJava并發編程:CountDownLatch、CyclicBarrier和Semaphore1) CountDownLatch和
40、CyclicBarrier都能夠實現線程之間的等待,只不過它們側重點不同:CountDownLatch一般用于某個線程A等待若干個其他線程執行完任務之后,它才執行;而CyclicBarrier一般用于一組線程互相等待至某個狀態,然后這一組線程再同時執行;另外,CountDownLatch是不能夠重用的,而CyclicBarrier是可以重用的。2)Semaphore其實和鎖有點類似,它一般用于控制對某組資源的訪問權限。1.3.4 說說 CyclicBarrier 原理參考:JUC回顧之-CyclicBarrier底層實現和原理1.3.5 說說 Semaphore 原理JAVA多線程信號量(Se
41、maphore)JUC回顧之-Semaphore底層實現和原理1.3.6 說說 Exchanger 原理java.util.concurrent.Exchanger應用范例與原理淺析1.3.7 說說 CountDownLatch 與 CyclicBarrier 區別CountDownLatchCyclicBarrier減計數方式加計數方式計算為0時釋放所有等待的線程計數達到指定值時釋放所有等待線程計數為0時,無法重置計數達到指定值時,計數置為0重新開始調用countDown()方法計數減一,調用await()方法只進行阻塞,對計數沒任何影響調用await()方法計數加1,若加1后的值不等于構造
42、方法的值,則線程阻塞不可重復利用可重復利用盡量把CyclicBarrier和CountDownLatch的區別說通俗點1.3.8 ThreadLocal 原理分析ThreadLocal不是用來解決對象共享訪問問題的,而主要是提供了保持對象的方法和避免參數傳遞的方便的對象訪問方式。歸納了兩點:1) 每個線程中都有一個自己的ThreadLocalMap類對象,可以將線程自己的對象保持到其中,各管各的,線程可以正確的訪問到自己的對象。2) 將一個共用的ThreadLocal靜態實例作為key,將不同對象的引用保存到不同線程的ThreadLocalMap中,然后在線程執行的各處通過這個靜態Thread
43、Local實例的get()方法取得自己線程保存的那個對象,避免了將這個對象作為參數傳遞的麻煩。Java并發編程:深入剖析ThreadLocal1.3.9 講講線程池的實現原理線程池的具體實現原理,將從下面幾個方面講解:1. 線程池狀態1) 當創建線程池后,初始時,線程池處于RUNNING狀態;2) 如果調用了shutdown()方法,則線程池處于SHUTDOWN狀態,此時線程池不能夠接受新的任務,它會等待所有任務執行完畢;3) 如果調用了shutdownNow()方法,則線程池處于STOP狀態,此時線程池不能接受新的任務,并且會去嘗試終止正在執行的任務;4) 當線程池處于SHUTDOWN或ST
44、OP狀態,并且所有工作線程已經銷毀,任務緩存隊列已經清空或執行結束后,線程池被設置為TERMINATED狀態。2. 任務的執行1) 首先,要清楚corePoolSize和maximumPoolSize的含義;2) 其次,要知道Worker是用來起到什么作用的;3) 要知道任務提交給線程池之后的處理策略,這里總結一下主要有4點:l 如果當前線程池中的線程數目小于corePoolSize,則每來一個任務,就會創建一個線程去執行這個任務;l 如果當前線程池中的線程數目>=corePoolSize,則每來一個任務,會嘗試將其添加到任務緩存隊列當中,若添加成功,則該任務會等待空閑線程將其取出去執行
45、;若添加失敗(一般來說是任務緩存隊列已滿),則會嘗試創建新的線程去執行這個任務;l 如果當前線程池中的線程數目達到maximumPoolSize,則會采取任務拒絕策略進行處理;l 如果線程池中的線程數量大于 corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止,直至線程池中的線程數目不大于corePoolSize;如果允許為核心池中的線程設置存活時間,那么核心池中的線程空閑時間超過keepAliveTime,線程也會被終止。3. 線程池中的線程初始化默認情況下,創建線程池之后,線程池中是沒有線程的,需要提交任務之后才會創建線程。在實際中如果需要線程池創建之
46、后立即創建線程,可以通過以下兩個方法辦到:l prestartCoreThread():初始化一個核心線程;l prestartAllCoreThreads():初始化所有核心線程注意上面傳進去的參數是null,如果傳進去的參數為null,則最后執行線程會阻塞在getTask方法中的workQueue.take();即等待任務隊列中有任務。4. 任務緩存隊列及排隊策略在前面我們多次提到了任務緩存隊列,即workQueue,它用來存放等待執行的任務。workQueue的類型為BlockingQueue<Runnable>,通常可以取下面三種類型:l ArrayBlockingQueu
47、e:基于數組的先進先出隊列,此隊列創建時必須指定大小;l LinkedBlockingQueue:基于鏈表的先進先出隊列,如果創建時沒有指定此隊列大小,則默認為Integer.MAX_VALUE;l synchronousQueue:這個隊列比較特殊,它不會保存提交的任務,而是將直接新建一個線程來執行新來的任務。5. 任務拒絕策略當線程池的任務緩存隊列已滿并且線程池中的線程數目達到maximumPoolSize,如果還有任務到來就會采取任務拒絕策略,通常有以下四種策略:l ThreadPoolExecutor.AbortPolicy:丟棄任務并拋出RejectedExecutionExcept
48、ion異常。 l ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出異常。 l ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程)l ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務6. 線程池的關閉ThreadPoolExecutor提供了兩個方法,用于線程池的關閉,分別是shutdown()和shutdownNow(),其中:l shutdown():不會立即終止線程池,而是要等所有任務緩存隊列中的任務都執行完后才終止,但再
49、也不會接受新的任務l shutdownNow():立即終止線程池,并嘗試打斷正在執行的任務,并且清空任務緩存隊列,返回尚未執行的任務7. 線程池容量的動態調整ThreadPoolExecutor提供了動態調整線程池容量大小的方法:setCorePoolSize()和setMaximumPoolSize(),l setCorePoolSize:設置核心池大小l setMaximumPoolSize:設置線程池最大能創建的線程數目大小當上述參數從小變大時,ThreadPoolExecutor進行線程賦值,還可能立即創建新的線程來執行任務。主要是ThreadPoolExecutor的實現原理Java
50、并發編程:線程池的使用1.3.10 線程池的幾種方式newFixedThreadPool(int nThreads) 創建一個固定長度的線程池,每當提交一個任務就創建一個線程,直到達到線程池的最大數量,這時線程規模將不再變化,當線程發生未預期的錯誤而結束時,線程池會補充一個新的線程newCachedThreadPool() 創建一個可緩存的線程池,如果線程池的規模超過了處理需求,將自動回收空閑線程,而當需求增加時,則可以自動添加新線程,線程池的規模不存在任何限制newSingleThreadExecutor() 這是一個單線程的Executor,它創建單個工作線程
51、來執行任務,如果這個線程異常結束,會創建一個新的來替代它;它的特點是能確保依照任務在隊列中的順序來串行執行newScheduledThreadPool(int corePoolSize) 創建了一個固定長度的線程池,而且以延遲或定時的方式來執行任務,類似于Timer。參考:創建線程池的幾種方式1.3.11 線程的生命周期新建(New)、就緒(Runnable)、運行(Running)、阻塞(Blocked)和死亡(Dead)5種狀態(1)生命周期的五種狀態新建(new Thread) 當創建Thread類的一個實例(對象)時,此線程進入新建狀態(未被啟動)。 例如
52、:Thread t1=new Thread();就緒(runnable) 線程已經被啟動,正在等待被分配給CPU時間片,也就是說此時線程正在就緒隊列中排隊等候得到CPU資源。例如:t1.start();運行(running) 線程獲得CPU資源正在執行任務(run()方法),此時除非此線程自動放棄CPU資源或者有優先級更高的線程進入,線程將一直運行到結束。死亡(dead) 當線程執行完畢或被其它線程殺死,線程就進入死亡狀態,這時線程不可能再進入就緒狀態等待執行。自然終止:正常運行run()方法后終止異常終止:調用stop()方法讓一個線程終止運行堵塞(blocke
53、d) 由于某種原因導致正在運行的線程讓出CPU并暫停自己的執行,即進入堵塞狀態。正在睡眠:用sleep(long t) 方法可使線程進入睡眠方式。一個睡眠著的線程在指定的時間過去可進入就緒狀態。正在等待:調用wait()方法。(調用motify()方法回到就緒狀態)被另一個線程所阻塞:調用suspend()方法。(調用resume()方法恢復)參考:線程的生命周期1.4 鎖機制1.4.1 說說線程安全問題線程安全是指要控制多個線程對某個資源的有序訪問或修改,而在這些線程之間沒有產生沖突。在Java里,線程安全一般體現在兩個方面:1) 多個thread對同一個java實例的訪問(rea
54、d和modify)不會相互干擾,它主要體現在關鍵字synchronized。如ArrayList和Vector,HashMap和Hashtable(后者每個方法前都有synchronized關鍵字)。如果你在interator一個List對象時,其它線程remove一個element,問題就出現了。2) 每個線程都有自己的字段,而不會在多個線程之間共享。它主要體現在java.lang.ThreadLocal類,而沒有Java關鍵字支持,如像static、transient那樣。1.4.2 volatile 實現原理Volatile是輕量級的synchronized,它在多處理器開發中保證了共享
55、變量的“可見性”。可見性的意思是當一個線程修改一個共享變量時,另外一個線程能讀到這個修改的值。它在某些情況下比synchronized的開銷更小,本文將深入分析在硬件層面上Inter處理器是如何實現Volatile的,通過深入分析能幫助我們正確的使用Volatile變量。聊聊并發(一)深入分析Volatile的實現原理1.4.3 悲觀鎖 樂觀鎖樂觀鎖 悲觀鎖 是一種思想。可以用在很多方面。比如數據庫方面。 悲觀鎖就是for update(鎖定查詢的行) 樂觀鎖就是 version字段(比較跟上一次的版本號,如果一樣則更新,如果失敗則要重復讀-比較-寫的操作。)JD
56、K方面: 悲觀鎖就是sync 樂觀鎖就是原子類(內部使用CAS實現)本質來說,就是悲觀鎖認為總會有人搶我的。 樂觀鎖就認為,基本沒人搶。1.4.4 CAS 樂觀鎖樂觀鎖是一種思想,即認為讀多寫少,遇到并發寫的可能性比較低,所以采取在寫時先讀出當前版本號,然后加鎖操作(比較跟上一次的版本號,如果一樣則更新),如果失敗則要重復讀-比較-寫的操作。CAS是一種更新的原子操作,比較當前值跟傳入值是否一樣,一樣則更新,否則失敗。 CAS頂多算是樂觀鎖寫那一步操作的一種實現方式罷了,不用CAS自己加鎖也是可以的。ABA 問題ABA:如果另一個線程修改V值假設原來是A
57、,先修改成B,再修改回成A,當前線程的CAS操作無法分辨當前V值是否發生過變化。參考:Java CAS 和ABA問題1.4.5 樂觀鎖的業務場景及實現方式樂觀鎖(Optimistic Lock): 每次獲取數據的時候,都不會擔心數據被修改,所以每次獲取數據的時候都不會進行加鎖,但是在更新數據的時候需要判斷該數據是否被別人修改過。如果數據被其他線程修改,則不進行數據更新,如果數據沒有被其他線程修改,則進行數據更新。由于數據沒有進行加鎖,期間該數據可以被其他線程進行讀寫操作。樂觀鎖:比較適合讀取操作比較頻繁的場景,如果出現大量的寫入操作,數據發生沖突的可能性就會增大,為了保證數據的一致性
58、,應用層需要不斷的重新獲取數據,這樣會增加大量的查詢操作,降低了系統的吞吐量。2 核心篇2.1 數據存儲2.1.1 MySQL 索引使用的注意事項參考:mysql索引使用技巧及注意事項2.1.2 說說反模式設計參考:每個程序員要注意的 9 種反模式2.1.3 說說分庫與分表設計分表與分庫使用場景以及設計方式2.1.4 分庫與分表帶來的分布式困境與應對之策服務端指南 數據存儲篇 | MySQL(09) 分庫與分表帶來的分布式困境與應對之策2.1.5 說說 SQL 優化之道sql優化的幾種方法2.1.6 MySQL 遇到的死鎖問題參考:Mysql并發時經典常見的死鎖原因及解決方法2.1.7 存儲引擎的 InnoDB 與 MyISAM1)InnoDB支持事務,MyISAM不支持,這一點是非常之重要。事務是一種高級的處理方式,如在一些列增刪改中只要哪個
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2022-2027年中國小龍蝦養殖行業市場深度分析及投資規劃建議報告
- 中國聚氨酯合成革行業發展監測及發展戰略規劃報告
- 2025年中國成型尼龍管行業市場發展前景及發展趨勢與投資戰略研究報告
- 2025年中國電子表鑰匙鏈行業市場發展前景及發展趨勢與投資戰略研究報告
- 2025年中國保溫板市場供需現狀及投資戰略研究報告
- 2025年光纖傳感器項目節能評估報告(節能專)
- 中國聚烯烴抗氧劑行業市場調查報告
- 中國非發酵豆制品行業市場全景分析及投資前景展望報告
- 純棉印花開肩內衣行業深度研究分析報告(2024-2030版)
- 2025年中國干冰煙霧機行業市場發展前景及發展趨勢與投資戰略研究報告
- 高三數學一輪復習題型與戰法精準訓練(新高考專用)7.2.2點線面的位置關系(針對練習)(原卷版+解析)
- 翻譯理論與實踐智慧樹知到期末考試答案章節答案2024年湖南中醫藥大學
- 2024年吉林省中考歷史試卷真題(含答案)
- 人教部編版三年級下冊語文【選擇題】專項復習訓練真題100題(附答案解析)
- 免檢車輛標志委托書
- 人教鄂教版科學18《制作日晷》課件-科學四年級下冊人教鄂教版
- 云南開放大學實-用寫作離線作業1-5
- 內科學(腎臟-內分泌-血液)智慧樹知到期末考試答案章節答案2024年溫州醫科大學
- 食品安全與日常飲食智慧樹知到期末考試答案章節答案2024年中國農業大學
- 信息安全、網絡安全和隱私保護-信息安全控制清單(2024A1-雷澤佳編制)
- 100以內進退位加減法口算題每天60道
評論
0/150
提交評論