1. 面向對象
什么是面向對象
-
面向對象與面向過程
始終圍繞如何解決具體問題進行扛邑。面向過程就是分析出解決問題所需要的步驟,然后用函數(shù)把這些步驟一步一步實現(xiàn)铐然,使用的時候一個一個依次調用就可以了蔬崩;
以更形象的方式在計算機中構建現(xiàn)實的事物,更符合人認識世界的習慣搀暑。面向對象是把構成問題事務分解成各個對象沥阳,建立對象的目的不是為了完成一個步驟,而是為了描敘某個事物在整個解決問題的步驟中的行為自点。
-
面向對象的三大基本特征和五大基本原則
特征:封裝桐罕,繼承,多態(tài)
原則:單一職責原則(SRP) 一個類應該有且只有一個去改變它的理由桂敛,這意味著一個類應該只有一項工作功炮。
開放封閉原則(OCP) 對象或實體應該對擴展開放,對修改封閉术唬。例如私有方法允許重載薪伏,但不允許重寫。
里氏替換原則(LSP) 在對象 x 為類型 T 時 q(x) 成立粗仓,那么當 S 是 T 的子類時毅该,對象 y 為類型 S 時 q(y) 也應成立博秫。(即對父類的調用同樣適用于子類)
依賴倒置原則(DIP) 高層次的模塊不應該依賴于低層次的模塊,他們都應該依賴于抽象眶掌。具體實現(xiàn)應該依賴于抽象挡育,而不是依賴于實現(xiàn)。依賴于實現(xiàn)會使得日后擴展不斷朴爬。例如A依賴于B即寒、C、D的實現(xiàn)不如依賴于BCD共同實現(xiàn)的接口或抽象類召噩。
接口隔離原則(ISP) 不應強迫客戶端實現(xiàn)一個它用不上的接口母赵,或是說客戶端不應該被迫依賴它們不使用的方法,使用多個專門的接口比使用單個接口要好的多具滴!
平臺無關性
-
Java 如何實現(xiàn)的平臺無關
java的運行依賴于java運行環(huán)境(JRE)凹嘲,Java雖然平臺無關但JRE是平臺相關的,雖然它支持大部分主流平臺构韵。
-
JVM 還支持哪些語言
(Kotlin周蹭、Groovy、JRuby疲恢、Jython凶朗、Scala)
值傳遞
-
值傳遞、引用傳遞
1.基本類型作為參數(shù)傳遞時显拳,是傳遞值的拷貝棚愤,無論你怎么改變這個拷貝,原值是不會改變的
2.對象作為參數(shù)傳遞時杂数,是把對象在內存中的地址拷貝了一份傳給了參數(shù)宛畦。
3.C++中還有指針傳遞。
-
為什么說Java中只有值傳遞揍移?
前述的引用傳遞刃永,形參拿到的是實參地址的復制,相當于是地址值的傳遞羊精。
Java中的引用傳遞相當于c++中的指針傳遞。至于C++中的引用傳遞解釋如下:引用參數(shù)傳遞過程中囚玫,被調函數(shù)的形式參數(shù)也作為局部變量在棧中開辟了內存空間喧锦,但是這時存放的是由主調函數(shù)放進來的實參變量的地址。被調函數(shù)對形參(本體)的任何操作都被處理成間接尋址抓督,即通過棧中存放的地址訪問主調函數(shù)中的實參變量(根據(jù)別名找到主調函數(shù)中的本體)燃少。因此,被調函數(shù)對形參的任何操作都會影響主調函數(shù)中的實參變量铃在。
2. java基礎知識
浮點數(shù)精度
浮點數(shù)在機器中的表示由三部分組成:符號阵具,指數(shù)碍遍,尾數(shù)。所以其最大精度由尾數(shù)位數(shù)來決定阳液。
包裝類型
包裝類型用于經基本類型轉換為一個對象怕敬,包裝類于基本類型之間的自動轉換稱為自動拆裝箱。
Integer的緩存機制
在 Java 5 中帘皿,為 Integer 的操作引入了一個新的特性东跪,用來節(jié)省內存和提高性能。整型對象在內部實現(xiàn)中通過使用相同的對象引用實現(xiàn)了緩存和重用鹰溜。上面的規(guī)則適用于整數(shù)區(qū)間 -128 到 +127虽填。這種 Integer 緩存策略僅在自動裝箱(autoboxing)的時候有用,使用構造器創(chuàng)建的 Integer 對象不能被緩存曹动。Java 編譯器把原始類型自動轉換為封裝類的過程稱為自動裝箱(autoboxing)斋日,這相當于調用 valueOf 方法。這種緩存行為不僅適用于Integer對象墓陈。我們針對所有整數(shù)類型的類都有類似的緩存機制恶守。
有 ByteCache 用于緩存 Byte 對象
有 ShortCache 用于緩存 Short 對象
有 LongCache 用于緩存 Long 對象
有 CharacterCache 用于緩存 Character 對象
Byte,Short跛蛋,Long 有固定范圍: -128 到 127熬的。對于 Character, 范圍是 0 到 127。除了 Integer 可以通過參數(shù)改變范圍外赊级,其它的都不行押框。
String
-
JDK 6 和 JDK 7 中 substring 的原理及區(qū)別
String是通過字符數(shù)組實現(xiàn)的。在jdk 6 中理逊,String類包含三個成員變量:char value[]橡伞, int offset,int count晋被。他們分別用來存儲真正的字符數(shù)組兑徘,數(shù)組的第一個位置索引以及字符串中包含的字符個數(shù)。
當調用substring方法的時候羡洛,會創(chuàng)建一個新的string對象挂脑,但是這個string的值仍然指向堆中的同一個字符數(shù)組。這兩個對象中只有count和offset 的值是不同的欲侮。
這樣做乍看起來可以減少內存占用崭闲,可是substring的存在會使得整個字符串在無用后得不到回收。所以在JDK7中substring實現(xiàn)方式變?yōu)殚_辟新的內存存儲子字符串威蕉。
-
字符串拼接的方式
加號“+”
String contact() 方法
StringUtils.join() 方法
StringBuffer append() 方法
StringBuilder append() 方法
-
stringbuild和stringbuffer的區(qū)別
在執(zhí)行速度方面的比較:StringBuilder > StringBuffer
StringBuffer與StringBuilder刁俭,他們是字符串變量,是可改變的對象韧涨,每當我們用它們對字符串做操作時牍戚,實際上是在一個對象上操作的侮繁,不像String一樣創(chuàng)建一些對象進行操作,所以速度就快了如孝。
StringBuilder:線程非安全的 StringBuffer:線程安全的
-
String.valueOf 和 Integer.toString 的區(qū)別
String.valueOf()對不同數(shù)據(jù)類型實現(xiàn)了重載宪哩,對于int類型的參數(shù)直接調用Integer.toString()
-
字符串池、常量池(運行時常量池暑竟、Class 常量池)斋射、intern
String有兩種賦值方式,第一種是通過“字面量”賦值但荤。
String str = "Hello";
第二種是通過new關鍵字創(chuàng)建新對象罗岖。
String str = new String("Hello");class常量池:我們寫的每一個Java類被編譯后,就會形成一份class文件腹躁;class文件中除了包含類的版本桑包、字段、方法纺非、接口等描述信息外哑了,還有一項信息就是常量池(constant pool tle),用于存放編譯器生成的各種字面量(Literal)和符號引用(Symbolic References)烧颖;
運行時常量池:運行時常量池存在于內存中弱左,也就是class常量池被加載到內存之后的版本,不同之處是:它的字面量可以動態(tài)的添加(String.intern()),符號引用可以被解析為直接引用.
字符串池為他們的一部分炕淮。字面量創(chuàng)建字符串會先在字符串池中找拆火,看是否有相等的對象,沒有的話就在堆中創(chuàng)建涂圆,把地址駐留在字符串池们镜;有的話則直接用池中的引用,避免重復創(chuàng)建對象润歉。
new關鍵字創(chuàng)建時模狭,前面的操作和字面量創(chuàng)建一樣,只不過最后在運行時會創(chuàng)建一個新對象踩衩,變量所引用的都是這個新對象的地址嚼鹉。
由于不同版本的JDK內存會有些變化,JDK1.6字符串常量池在永久代(即方法區(qū))驱富,1.7移到了堆中(與運行時常量池分開)锚赤,1.8用元空間代替了永久代。但是基本對上面的結論沒有影響萌朱,思想是一樣的。
各種關鍵字
-
transient策菜、instanceof晶疼、final酒贬、static、volatile翠霍、synchronized锭吨、const 原理及用法
transient 表示無需序列化的變量
final可以用來修飾類(繼承),方法(重寫)和變量(const)(成員變量或局部變量)
finally作為異常處理的一部分寒匙,它只能用在try/catch語句中
finalize()是在java.lang.Object里定義的零如,也就是說每一個對象都有這么個方法。這個方法在gc啟動锄弱,該對象被回收的時候被調用
集合類
-
ArrayList 和 LinkedList 和 Vector 的區(qū)別
ArrayList和Vector都是基于數(shù)組實現(xiàn)的考蕾,但Vector實現(xiàn)了線程安全所以他效率會低,linkedList是基于雙向列表實現(xiàn)的会宪。還有synchronizedList肖卧,是實現(xiàn)了線程安全的ArrayList,所以與Vector的區(qū)別僅僅是增長速度掸鹅。
-
HashMap塞帐、HashTable、ConcurrentHashMap 區(qū)別
Hashtable和HashMap有幾個主要的不同:線程安全以及速度巍沙。僅在你需要完全的線程安全的時候使用Hashtable葵姥,而如果你使用Java 5或以上的話,請使用ConcurrentHashMap吧句携。
-
HashSet是如何保證元素唯一性的呢榔幸?
是通過元素的兩個方法,hashCode和equals來完成务甥。
如果元素的HashCode值相同牡辽,才會判斷equals是否為true。
如果元素的hashcode值不同敞临,不會調用equals态辛。
-
Java 8 中 stream 相關用法
Stream 就如同一個迭代器(Iterator),單向挺尿,不可往復奏黑,數(shù)據(jù)只能遍歷一次,遍歷過一次后即用盡了编矾,就好比流水從面前流過熟史,一去不復返≌危可以并行化處理蹂匹。
常用操作有 filter map distinct 排序 reduction collect
-
apache 集合處理工具類的使用
并交補、過濾凹蜈、collect(獲取某些屬性的集合)
-
不同版本的 JDK 中 HashMap 的實現(xiàn)的區(qū)別以及原因
JDK1.8之前處理hash沖突使用鏈表限寞,但是鏈表查詢滿忍啸,鏈表長了之后效率會下降,故JDK1.8之后鏈表長度達到一定閾值后轉換為紅黑樹履植,紅黑樹增刪慢计雌,查詢快。
-
Collection與Collections
java.util.Collection 是一個集合接口(集合類的一個頂級接口)
Collections則是集合類的一個工具類/幫助類玫霎,其中提供了一系列靜態(tài)方法凿滤,用于對集合中元素進行排序、搜索以及線程安全等各種操作庶近。
-
Arrays.asList
是不支持add和remove操作的翁脆,也就是說Arrays.asList返回的List是個固定大小的List。如果希望轉過后的list可以支持add和remove操作拦盹,可使用如下方法:
ArrayList<Integer> copyArrays=new ArrayList<>(Arrays.asList(integerArray));
-
Enumeration 和 Iterator 區(qū)別
Iterator除了能讀取集合的數(shù)據(jù)之外鹃祖,也能數(shù)據(jù)進行刪除操作。
Iterator支持fail-fast機制普舆,而Enumeration不支持恬口。
-
fail-fast 和 fail-safe
在使用迭代器遍歷集合時,若集合內容發(fā)生改變沼侣,而我們接著對該集合遍歷祖能,此事是否應該拋出異常?快速失敗就是即刻拋出Concurrent Modification Exception蛾洛。而安全失敗的遍歷是在遍歷之前將集合內容復制出來养铸,在其上進行遍歷。
-
CopyOnWrite容器
CopyOnWrite容器即寫時復制的容器轧膘。通俗的理解是當我們往一個容器添加元素的時候钞螟,不直接往當前容器添加,而是先將當前容器進行Copy谎碍,復制出一個新的容器鳞滨,然后新的容器里添加元素,添加完元素之后蟆淀,再將原容器的引用指向新的容器拯啦。這樣做的好處是我們可以對CopyOnWrite容器進行并發(fā)的讀,而不需要加鎖熔任,因為當前容器不會添加任何元素褒链。所以CopyOnWrite容器也是一種讀寫分離的思想,讀和寫不同的容器
-
ConcurrentSkipListMap
TreeMap使用紅黑樹按照key的順序(自然順序疑苔、自定義順序)來使得鍵值對有序存儲甫匹,但是只能在單線程下安全使用;多線程下想要使鍵值對按照key的順序來存儲,則需要使用ConcurrentSkipListMap兵迅。 ConcurrentSkipListMap的底層是通過跳表來實現(xiàn)的哀墓。
-
同步、異步喷兼、阻塞、非阻塞
同步異步是指進程通信方式后雷,阻塞非阻塞是指同步之下進程能否繼續(xù)執(zhí)行其他任務季惯。
linux下的五種I/O模型
1)阻塞I/O(blocking I/O)
2)非阻塞I/O(nonblocking I/O)
3)I/O復用(select 和poll) (I/O multiplexing)
I/O復用模型會用到select、poll臀突、epoll函數(shù)勉抓,這幾個函數(shù)也會使進程阻塞,但是和阻塞I/O所不同的的候学,這兩個函數(shù)可以同時阻塞多個I/O操作
4)信號驅動I/O (signal driven I/O (SIGIO))
在信號處理函數(shù)中調用I/O操作函數(shù)處理數(shù)據(jù),進程繼續(xù)運行并不阻塞
5)異步I/O (asynchronous I/O (the POSIX aio_functions))
實際處理這個調用的部件在完成后,通過狀態(tài)捕儒、通知和回調來通知調用者的輸入輸出操作
前者與后者的區(qū)別在于啟用異步I/O意味著通知內核啟動某個I/O操作望几,并讓內核在整個操作(包括數(shù)據(jù)從內核復制到用戶緩沖區(qū))完成時通知我們。也就是說掰茶,異步I/O是由內核通知我們I/O操作何時完成暇藏,即實際的I/O操作也是異步的;而 信號驅動I/O是由內核通知我們何時可以啟動一個I/O
-
select濒蒋、epoll
select的幾大缺點及epoll解決方式:
1.每次循環(huán)調用select盐碱,都需要把fd集合從用戶態(tài)拷貝到內核態(tài),返回時從內核態(tài)拷貝到用戶態(tài)沪伙,這個開銷在fd很多時會很大(epoll的解決方案-在epoll_ctl函數(shù)中瓮顽。每次注冊新的事件到epoll句柄中時(在epoll_ctl中指定EPOLL_CTL_ADD),會把所有的fd拷貝進內核围橡,而不是在循環(huán)調用epoll_wait的時候重復拷貝暖混。epoll保證了每個fd在整個過程中只會拷貝一次。)
2.同時每次調用select都需要在內核遍歷傳遞進來的所有fd某饰,這個開銷在fd很多時也很大(epoll的解決方案不像select或poll一樣每次都把current輪流加入fd對應的設備等待隊列中儒恋,而只在epoll_ctl時把current掛一遍(這一遍必不可少)并為每個fd指定一個回調函數(shù),當設備就緒黔漂,喚醒等待隊列上的等待者時诫尽,就會調用這個回調函數(shù),而這個回調函數(shù)會把就緒的fd加入一個就緒鏈表)炬守。epoll_wait的工作實際上就是在這個就緒鏈表中查看有沒有就緒的fd(利用schedule_timeout()實現(xiàn)睡一會牧嫉,判斷一會的效果,和select實現(xiàn)中的第7步是類似的))
3.select支持的文件描述符數(shù)量太小了,默認是1024(fd_set只包含一個int數(shù)組酣藻,數(shù)組大小為1024)
-
BIO曹洽、NIO、AIO
BIO
NIO的最重要的地方是當一個連接創(chuàng)建后辽剧,不需要對應一個線程送淆,這個連接會被注冊到多路復用器上面,所以所有的連接只需要一個線程就可以搞定怕轿,當這個線程中的多路復用器進行輪詢的時候偷崩,發(fā)現(xiàn)連接上有請求的話,才開啟一個線程進行處理撞羽,也就是一個請求一個線程模式阐斜。也就是說,這個時候诀紊,已經不是一個連接就要對應一個處理線程了谒出,而是有效的請求,對應一個線程邻奠,當連接沒有數(shù)據(jù)時笤喳,是沒有工作線程來處理的。netty基于此
AIO與NIO不同碌宴,當進行讀寫操作時莉测,只須直接調用API的read或write方法即可。這兩種方法均為異步的唧喉,對于讀操作而言捣卤,當有流可讀取時,操作系統(tǒng)會將可讀的流傳入read方法的緩沖區(qū)八孝,并通知應用程序董朝;對于寫操作而言,當操作系統(tǒng)將write方法傳遞的流寫入完畢時干跛,操作系統(tǒng)主動通知應用程序子姜。 即可以理解為,read/write方法都是異步的楼入,完成后會主動調用回調函數(shù)哥捕。
反射
-
反射與工廠模式,IOC
將反射與工廠模式結合嘉熊,可以通過類名字(查找類文件)便能生成對象遥赚。可以動態(tài)加入類文件阐肤。
class Factory{ public static fruit getInstance(String ClassName){ fruit f=null; try{ f=(fruit)Class.forName(ClassName).newInstance(); }catch (Exception e) { e.printStackTrace(); } return f; } }
我們可以把IOC(控制反轉)容器的工作模式看做是工廠模式的升華凫佛,可以把IOC容器看作是一個工廠讲坎,這個工廠里要生產的對象都在配置文件中給出定義,然后利用編程語言提供的反射機制愧薛,根據(jù)配置文件中給出的類名生成相應的對象晨炕。從實現(xiàn)來看,IOC是把以前在工廠方法里寫死的對象生成代碼毫炉,改變?yōu)橛膳渲梦募矶x瓮栗,也就是把工廠和對象生成這兩者獨立分隔開來,目的就是提高靈活性和可維護性
代理
靜態(tài)代理
public void execute() { System.out.println("前攔截..."); bussinessImpl.execute(); System.out.println("后攔截..."); }
動態(tài)代理瞄勾,無需手動實現(xiàn)每個接口遵馆,只需添加對方法的判斷
public Object getProxyInstance(){ return Proxy.newProxyInstance( targetObject.getClass().getClassLoader(), //和目標對象的類加載器保持一致 targetObject.getClass().getInterfaces(), //目標對象實現(xiàn)的接口,因為需要根據(jù)接口動態(tài)生成對象 new InvocationHandler() { //InvocationHandler:事件處理器丰榴,即對目標對象方法的執(zhí)行 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("前攔截..."); Object result = method.invoke(proxy, args); System.out.println("后攔截..."); return result; } });
動態(tài)代理類并不是程序員寫的,而是根據(jù)傳入的參數(shù)秆撮,由Proxy類在運行時生成的四濒。
有一點必須注意:jdk動態(tài)代理的應用前提,必須是目標類基于統(tǒng)一的接口职辨?盗蟆。如果沒有上述前提,jdk動態(tài)代理不能應用舒裤。由此可以看出喳资,jdk動態(tài)代理有一定的局限性,cglib這種第三方類庫實現(xiàn)的動態(tài)代理應用更加廣泛腾供,且在效率上更有優(yōu)勢
序列化
-
Java序列化底層原理
-
protobuf
相對于XML仆邓,protocol buffers在序列化結構數(shù)據(jù)時擁有許多先進的特性:
1、更簡單
2伴鳖、序列化后字節(jié)占用空間比XML少3-10倍
3节值、序列化的時間效率比XML快20-100倍
4、具有更少的歧義性
5榜聂、自動生成數(shù)據(jù)訪問類方便應用程序的使用
JMS
-
什么是JMS
JMS 原本就是一個異步的消息服務搞疗,客戶端獲取消息的時候,不需要主動發(fā)送請求须肆,消息會自動發(fā)送給可用的客戶端
-
Kafka
泛型
泛型的目的簡單地說就是可以讓一些運行時才能發(fā)現(xiàn)的錯誤可以在編譯期間就可以被編譯器所檢測出匿乃,運行時出問題的代價與編譯期出現(xiàn)問題的代價的差別可想而知。換句話說豌汇,泛型是編譯器的一種及時發(fā)現(xiàn)錯誤的機制幢炸,同時也給用戶帶來了代碼的清晰與簡潔的附加好處
-
泛型與繼承
public class Solution<T> extends HashMap<Integer, T> { void push(Entry<Integer, T> x){ super.put(x.getKey(),x.getValue()); } public static void main(String[] args){ Solution<Integer> b2 = new Solution<>(); Entry<Integer, Integer> x = new SimpleEntry<>(1,2); b2.push(x); } }
-
類型擦除
Java 的泛型在編譯器有效,在運行期被刪除拒贱,也就是說所有泛型參數(shù)類型在編譯后都會被清除掉
List<String>阳懂、List<T>擦除后的類型為 List。
List<String>[]、List<T>[] 擦除后的類型為 List[]岩调。
List<? extends E>巷燥、List<? super E> 擦除后的類型為 List<E>。
List<T extends Serialzable & Cloneable> 擦除后類型為List<Serializable>号枕。
-
限定通配符和非限定通配符缰揪、上下界限定符 extends 和 super
-
List<Object>、原始類型 List葱淳、list<?>
list<Object>表示列表中可以存放任意類型的元素钝腺,List<?>表示該列表中的元素類型可以是任一相同類型,即他是List<E>的父類赞厕,為了保證類型安全艳狐,不允許對List<?>或List<? extends E>這樣的通配符類型進行類似add的操作。
相對于List皿桑,List<Object>可以幫助編譯器在編譯階段發(fā)現(xiàn)錯誤毫目。
測試
-
mock、mockito
API诲侮、SPI
API (Application Programming Interface)
大多數(shù)情況下镀虐,都是實現(xiàn)方來制定接口并完成對接口的不同實現(xiàn),調用方僅僅依賴卻無權選擇不同實現(xiàn)沟绪。
SPI (Service Provider Interface)
而如果是調用方來制定接口刮便,實現(xiàn)方來針對接口來實現(xiàn)不同的實現(xiàn)。調用方來選擇自己需要的實現(xiàn)方绽慈。
語法糖
語法糖:switch 支持 String 與枚舉恨旱、泛型、自動裝箱與拆箱坝疼、方法變長參數(shù)窖杀、枚舉、內部類裙士、條件編譯入客、 斷言、數(shù)值字面量腿椎、for-each桌硫、try-with-resource、Lambda 表達式
并發(fā)編程
-
創(chuàng)建線程的幾種方式
一般有四種方法啃炸,Thread,Runnable,Callable,使用Executor框架來創(chuàng)建線程池.
Runnable和Callable的區(qū)別是铆隘,
(1)Callable規(guī)定的方法是call(),Runnable規(guī)定的方法是run().
(2)Callable的任務執(zhí)行后可返回值,而Runnable的任務是不能返回值得
(3)call方法可以拋出異常南用,run方法不可以
(4)運行Callable任務可以拿到一個Future對象膀钠,表示異步計算的結果掏湾。它提供了檢查計算是否完成的方法,以等待計算的完成肿嘲,并檢索計算的結果融击。通過Future對象可以了解任務執(zhí)行情況,可取消任務的執(zhí)行雳窟,還可獲取執(zhí)行結果尊浪。
一般來說,CachedTheadPool在程序執(zhí)行過程中通常會創(chuàng)建與所需數(shù)量相同的線程封救,然后在它回收舊線程時停止創(chuàng)建新線程拇涤,因此它是合理的Executor的首選,只有當這種方式會引發(fā)問題時(比如需要大量長時間面向連接的線程時)誉结,才需要考慮用FixedThreadPool
-
守護線程
Java的線程分為兩種:User Thread(用戶線程)鹅士、DaemonThread(守護線程)。
只要當前JVM實例中尚存任何一個非守護線程沒有結束惩坑,守護線程就全部工作掉盅;只有當最后一個非守護線程結束是,守護線程隨著JVM一同結束工作旭贬,Daemon作用是為其他線程提供便利服務,守護線程最典型的應用就是GC(垃圾回收器)搪泳,他就是一個很稱職的守護者稀轨。
User和Daemon兩者幾乎沒有區(qū)別,唯一的不同之處就在于虛擬機的離開:如果 User Thread已經全部退出運行了岸军,只剩下Daemon Thread存在了奋刽,虛擬機也就退出了。 因為沒有了被守護者艰赞,Daemon也就沒有工作可做了佣谐,也就沒有繼續(xù)運行程序的必要了。
public class DaemonThreadTest
{
public static void main(String[] args)
{
Thread mainThread = new Thread(new Runnable(){
@Override
public void run()
{
Thread childThread = new Thread(new ClildThread());
childThread.setDaemon(true);
childThread.start();
System.out.println("I'm main thread...");
}
});
mainThread.start();
Thread otherThread = new Thread(new Runnable(){
@Override
public void run()
{
while(true)
{
System.out.println("I'm other user thread...");
try
{
TimeUnit.MILLISECONDS.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
});
otherThread.start();
}
}
class ClildThread implements Runnable
{
@Override
public void run()
{
while(true)
{
System.out.println("I'm child thread..");
try
{
TimeUnit.MILLISECONDS.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
還有補充一點方妖,不是說當子線程是守護線程狭魂,主線程結束,子線程就跟著結束党觅,這里的前提條件是:當前jvm應用實例中沒有用戶線程繼續(xù)執(zhí)行雌澄,如果有其他用戶線程繼續(xù)執(zhí)行,那么后臺線程不會中斷杯瞻,如下:
public class DaemonThreadTest
{
public static void main(String[] args)
{
Thread mainThread = new Thread(new Runnable(){
@Override
public void run()
{
Thread childThread = new Thread(new ClildThread());
childThread.setDaemon(true);
childThread.start();
System.out.println("I'm main thread...");
}
});
mainThread.start();
Thread otherThread = new Thread(new Runnable(){
@Override
public void run()
{
while(true)
{
System.out.println("I'm other user thread...");
try
{
TimeUnit.MILLISECONDS.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
});
otherThread.start();
}
}
class ClildThread implements Runnable
{
@Override
public void run()
{
while(true)
{
System.out.println("I'm child thread..");
try
{
TimeUnit.MILLISECONDS.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
-
線程池不允許使用 Executors 去創(chuàng)建,而是通過ThreadPoolExecutor 的方式
-
線程安全與內存模型
-
死鎖出現(xiàn)的條件
- 互斥條件:一個資源每次只能被一個線程使用睬涧。
- 請求與保持條件:一個進程因請求資源而阻塞時募胃,對已獲得的資源保持不放。
- 不可剝奪條件:進程已獲得的資源畦浓,在未使用完之前痹束,不能強行剝奪。
- 循環(huán)等待條件:若干進程之間形成一種頭尾相接的循環(huán)等待資源關系宅粥。
-
銀行家算法
框架
hibernate
-
懶加載
實現(xiàn)懶加載的前提:
1.實體類不能是final的
2.能實現(xiàn)懶加載的對象都是被CGLIB(反射調用)改寫的代理對象,所以不能是final修飾的
3.須要asm,cglib兩個jar包
4.相應的lazy屬性為true
5.相應的fetch屬性為select
下面幾種可以實現(xiàn)懶加載功能:
1.通過Session.load()實現(xiàn)懶加載
2.one-to-one,many-to-one,one-to-many参袱。
因為懶加載的存在,在session關閉之后秽梅,hibernate又向數(shù)據(jù)庫發(fā)出一次請求抹蚀,結果就拋出異常.解決這個問題的四種方式:
1.Hibernate.initialize(Department.class);
2.修改對象關系文件,將lazy改寫lazy=false企垦,即關閉懶加載
3.使用過濾器(web項目)
4.在SSH框架中环壤,使用spring提供的openSessionView
mysql
-
四種事務隔離級別
臟讀:事務中讀到其他事務修改中間的數(shù)據(jù),若其他事務回滾了钞诡,那就讀到了臟數(shù)據(jù)
不可重復讀:事務多次重復讀取數(shù)據(jù)郑现,數(shù)據(jù)中途卻被其他事務修改
幻讀:事務A首先根據(jù)條件索引得到N條數(shù)據(jù),然后事務B改變了這N條數(shù)據(jù)之外的M條或者增添了M條符合事務A搜索條件的數(shù)據(jù)荧降,導致事務A再次搜索發(fā)現(xiàn)有N+M條數(shù)據(jù)了接箫,就產生了幻讀
-
引擎
innodb
支持“ACID”事務
鎖的粒度小,支持行鎖定(只在可以確定主鍵時)朵诫,所以適合經常更新的表辛友,適合處理多重并發(fā)的更新請求
支持外鍵約束
不支持fulltext索引
必須導出SQL來備份
myisam
大批量的插入語句時(這里是INSERT語句)執(zhí)行的比較的快
極度強調快速讀取操作。
如果表的讀操作遠遠多于寫操作且不需要數(shù)據(jù)庫事務的支持剪返,那么MyIASM也是很好的選擇废累。
允許沒有主鍵和索引的表
MyISAM的數(shù)據(jù)是以文件的形式存儲,所以在跨平臺的數(shù)據(jù)轉移中會很方便
一個強調的是性能脱盲,一個強調的是大容量數(shù)據(jù)庫的事務安全
-
索引數(shù)據(jù)結構
B-與B+的區(qū)別
B-每個非葉子結點由n-1個key和n個指針組成邑滨,其中d<=n<=2d;B+每個結點的指針上限為2d
B+內結點不存儲data钱反,只存儲key掖看;葉子結點不存儲指針。
-
為何使用B-/+來實現(xiàn)索引
可以將一個節(jié)點的大小設為一個頁面面哥,每個節(jié)點一次I/O便可讀入內存乙各,便于磁盤I/O
每次查找,最大的節(jié)點訪問數(shù)為h(樹高)幢竹,而h的大小與非葉節(jié)點的出度d有關耳峦,d增大,便可以減少磁盤I/O
另外焕毫,在B+Tree的每個葉子結點增加一個指向相鄰葉子結點的指針蹲坷,就形成了帶有順序訪問指針的B+Tree驶乾。做這個優(yōu)化的目的是為了提高區(qū)間訪問的性能,例如圖4中如果要查詢key為從18到49的所有數(shù)據(jù)記錄循签,當找到18后级乐,只需順著結點和指針順序遍歷就可以一次性訪問到所有數(shù)據(jù)結點,極大提到了區(qū)間查詢效率县匠。
-
innodb與myisam索引區(qū)別
myisam節(jié)點data域存放的是數(shù)據(jù)的地址风科,innodb主鍵索引中節(jié)點data域存放的直接是數(shù)據(jù),輔助索引data域存放主鍵乞旦,然后根據(jù)主鍵再進行一次主鍵索引找到非主鍵列贼穆。
-
覆蓋索引
前面說到innodb使用非主鍵索引時需要進行兩次索引,第二次索引叫回表兰粉,當所查詢數(shù)據(jù)為主鍵時是不需要回表的故痊,如下1
1.select id from user_table where username = 'lzs' 2.select password from user_table where username = 'lzs'
面對2這樣的查詢?yōu)榱思涌觳樵兯俣取玖姑?梢越⒙?lián)合索引愕秫,也叫覆蓋索引
-
最左前綴索引
繼續(xù)以上面的例子來說明,為了提高語句B的執(zhí)行速度焰络,我們添加了一個聯(lián)合索引(username,password),特別注意這個聯(lián)合索引的順序戴甩,如果我們顛倒下順序改成(password,username),這樣查詢能使用這個索引嗎?答案是不能的闪彼!這是最左前綴的第一層含義:聯(lián)合索引的多個字段中甜孤,只有當查詢條件為聯(lián)合索引的一個字段時,查詢才能使用該索引备蚓。
最左前綴的第二層含義:索引可以用于查詢條件字段為索引字段课蔬,根據(jù)字段值最左若干個字符進行的模糊查詢囱稽。1.where username like '張%' 2.where username like '%張%'
-
列中存在重復數(shù)據(jù)時郊尝,索引是什么結構的?
聚合索引要求非空唯一战惊,如果沒有滿足字段則會自建一列用作聚合索引流昏,非聚合索引(普通索引)葉節(jié)點指向聚合索引的鍵,不存在索引重復數(shù)據(jù)問題
值重復率高的字段不適合建索引吞获,從性別字段不適合建索引說起
-
count(*)與索引
當利用主鍵索引(聚集索引)來進行統(tǒng)計效率一般會小于利用二級索引况凉,這是因為count(*)主要的操作是在B+索引樹的葉節(jié)點上進行掃描,頁節(jié)點越小所需的磁盤IO便越少各拷,而聚集索引需要掃描整個數(shù)據(jù)文件刁绒。
mysql中的鎖
-
行級鎖
mysql中的行級鎖不是在表上加鎖,而是在索引上面加鎖烤黍,所以只有使用了索引的操作才有可能加行鎖知市,另外行級鎖有幾率出現(xiàn)死鎖傻盟。
[mysql行級鎖與表所鎖]
(https://www.cnblogs.com/guanghe/p/9217421.html)
-
間隙鎖
可以用來防止幻讀
innodb在RR級別快照讀模式下使用MVCC解決幻讀,在當前讀(insert嫂丙、update都屬于當前讀)模式下使用next-key lock娘赴。在唯一索引上(如主鍵索引),只需加record lock(記錄鎖)即可跟啤,在非唯一索引上需要加next-key鎖(record lock+gap lock)诽表,如班級=12,光加行鎖還是會使前后兩次select * from student where 班級=12結果出現(xiàn)幻讀