java面試常問問題及部分答案(2018)
1.簡述string對象,StringBuffer、StringBuilder區分
string是final的,內部用一個final類型的char數組存儲數據,它的拼接效率比較低,實際上是通過建立一個StringBuffer,讓後臺調用append(),最後再將StringBuffer toSting(),每次操作Sting 都會重新建立新的對象來保存新的值.這樣原來的對象就沒用了,就要被垃圾回收.這也是要影響性能的。
StringBuffer也是final,線程安全的,中采用一個char數組來保存需要append的字符串,char數組有一個初始大小,當append的字符串長度超過當前char數組容量時,則對char數組進行動態擴展,也即重新申請一段更大的內存空間,然後將當前char數組拷貝到新的位置,因為重新分配內存並拷貝的開銷比較大,所以每次重新申請內存空間都是采用申請大於當前需要的內存空間的方式,這裏是2倍。
2.多態的原理
多態就是:允許基類的指針或引用指向派生類的對象,而在具體訪問時實現方法的動態綁定。
原理是java的後期綁定。
3.簡要描述面向對象編程的思想
抽象:通過特定的實例抽取出共同的特征以後形成的概念的過程,它強調主要特征和忽略次要特征。
封裝:把對象的屬性和方法結合成一個獨立的整體,隱藏實現細節,並提供對外訪問的接口。
繼承:從已知的一個類中派生出新的一個類,叫子類。子類實現了父類所有非私有化屬性和方法,
並能根據自己的實際需求擴展出新的行為。
多態:多個不同的對象對同一消息作出響應,同一消息根據不同的對象而采用各種不同的行為方法。
4.反射的原理
java虛擬機運行時內存有個叫方法區,主要作用是存儲被裝載的類的類型信息。每裝載一個類的時候,java就會創建一個該類的Class對象實例。我們就可以通過這個實例,來訪問這個類的信息。
5.代理的作用和實現
代理模式的作用是:為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個客戶不想或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。
java的靜態代理和動態代理(略)
6.hashcode和equals的用法
Java對於eqauls方法和hashCode方法是這樣規定的:
如果兩個對象相同,那麽它們的hashCode值一定要相同;
如果兩個對象的hashCode相同,它們並不一定相同(上面說的對象相同指的是用eqauls方法比較。)
一般在覆蓋equals()方法的同時也要覆蓋hashCode()方法,否則,就會違反Object.hashCode的通用約定,從而導致該類無法與所有基於散列值(hash)集合類(HashMap、HashSet和Hashtable)結合在一起正常運行。
7.set,map,list的區別(盡量詳細)
map:
hashmap:鏈地址法,大概思路:通過取key的hashCode值、高位運算、取模運算計算位置,插入位置是通過hascode和eques方法判斷key是否一致
①.判斷鍵值對數組table[i]是否為空或為null,否則執行resize()進行擴容;
②.根據鍵值key計算hash值得到插入的數組索引i,如果table[i]==null,直接新建節點添加,轉向⑥,如果table[i]不為空,轉向③;
③.判斷table[i]的首個元素是否和key一樣,如果相同直接覆蓋value,否則轉向④,這裏的相同指的是hashCode以及equals;
④.判斷table[i] 是否為treeNode,即table[i] 是否是紅黑樹,如果是紅黑樹,則直接在樹中插入鍵值對,否則轉向⑤;
⑤.遍歷table[i],判斷鏈表長度是否大於8,大於8的話把鏈表轉換為紅黑樹,在紅黑樹中執行插入操作,否則進行鏈表的插入操作;遍歷過程中若發現key已經存在直接覆蓋value即可;
⑥.插入成功後,判斷實際存在的鍵值對數量size是否超多了最大容量threshold,如果超過,進行擴容。
treemap:TreeMap實現SortedMap接口,能夠把它保存的記錄根據鍵排序,默認是按鍵值的升序排序,也可以指定排序的比較器,當用Iterator遍歷TreeMap時,得到的記錄是排過序的。如果使用排序的映射,建議使用TreeMap。在使用TreeMap時,key必須實現Comparable接口或者在構造TreeMap傳入自定義的Comparator,否則會在運行時拋出java.lang.ClassCastException類型的異常。
linkedHashMap:保存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的,也可以在構造時帶參數,按照訪問次序排序。
HashTable:因為內部是采用synchronized來保證線程安全的
CocurrentHashMap:利用鎖分段技術增加了鎖的數目,從而使爭奪同一把鎖的線程的數目得到控制。
set:
HashSet:內部new了一個hashMap,添加時key放數據,value放一個內部定義的final的Object對象
LinkedHashSet:內部new了一個linkHashMap,添加時key放數據,value放一個內部定義的final的Object對象,遍歷時有序
TreeSet:內部new了一個TreeMap,添加時key放數據,value放一個內部定義的final的Object對象.
list:
arraylist和linkedList(略)
copywriteList:CopyOnWriteArrayList適合使用在讀操作遠遠大於寫操作的場景裏
8.
Integer demo1 = 100;
int demo2 = 100;
Integer demo3 = 10000;
int demo4 = 10000;
Integer demo5 = 100;
Integer demo6 = 100;
Integer demo7 = 10000;
Integer demo8 = 10000;
int demo10=10000;
int demo9=10000;
System.out.println(demo1==demo2);
System.out.println(demo3==demo4);
System.out.println(demo5==demo6);
System.out.println(demo7==demo8);
System.out.println(demo9==demo10);
結果:
true 自動拆箱裝箱 比大小
true 自動拆箱裝箱 比大小
true java常量池緩存一個引用
false 兩個引用
true 比大小
9.快速失敗和安全失敗
快速失敗和安全失敗是對叠代器而言的。 快速失敗:當在叠代一個集合的時候,如果有另外一個線程在修改這個集合,就會拋出ConcurrentModification異常,java.util下都是快速失敗。 安全失敗:在叠代時候會在集合二層做一個拷貝,所以在修改集合上層元素不會影響下層。在java.util.concurrent下都是安全失敗
二:java多線程
1.實現多線程的方式
繼承Thread類,重寫run方法
實現Runnable接口,重寫run方法,實現Runnable接口的實現類的實例對象作為Thread構造函數的target
通過Callable和FutureTask創建線程
通過線程池創建線程
2.多線程的狀態、流程圖
3.線程池
ThreadPoolExecutor
構造方法參數講解
參數名 作用
corePoolSize 隊列沒滿時,線程最大並發數
maximumPoolSizes 隊列滿後線程能夠達到的最大並發數
keepAliveTime 空閑線程過多久被回收的時間限制
unit keepAliveTime 的時間單位
workQueue 阻塞的隊列類型
RejectedExecutionHandler 超出 maximumPoolSizes + workQueue 時,任務會交給RejectedExecutionHandler來處理
文字描述
corePoolSize,maximumPoolSize,workQueue之間關系。
當線程池中線程數小於corePoolSize時,新提交任務將創建一個新線程執行任務,即使此時線程池中存在空閑線程。
當線程池中線程數達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行 。
當workQueue已滿,且maximumPoolSize > corePoolSize時,新提交任務會創建新線程執行任務。
當workQueue已滿,且提交任務數超過maximumPoolSize,任務由RejectedExecutionHandler處理。
當線程池中線程數超過corePoolSize,且超過這部分的空閑時間達到keepAliveTime時,回收這些線程。
當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize範圍內的線程空閑時間達到keepAliveTime也將回收。
newCachedThreadPool:無限大小線程池。重用之前已構造的可用線程,如果不存在可用線程,那麽會重新創建一個新的線程並將其加入到線程池中。如果線程超過 60 秒還未被使用,就會被中止並從緩存中移除。因此,線程池在長時間空閑後不會消耗任何資源。
FixedThreadPool:復用固定數量的線程 處理一個 共享的無邊界隊列 。任何時間點,最多有 nThreads 個線程會處於活動狀態執行任務。如果當所有線程都是活動時,有多的任務被提交過來,那麽它會一致在隊列中等待直到有線程可用。如果任何線程在執行過程中因為錯誤而中止,新的線程會替代它的位置來執行後續的任務。
SingleThreadPool 是通過 java.util.concurrent.Executors 創建的 ThreadPoolExecutor 實例。這個實例只會使用單個工作線程來執行一個無邊界的隊列。(註意,如果單個線程在執行過程中因為某些錯誤中止,新的線程會替代它執行後續線程)
4.多線程yield()、sleep()、wait()、join()
wait()和notify/notifyAll方法屬於object方法。
wait():wait方法依賴於同步,wait方法則需要釋放鎖。
yield()、sleep(),join()屬於Thread類方法。
sleep():可以直接調用。而更深層次的區別在於sleep方法只是暫時讓出CPU的執行權,並不釋放鎖。
yield():yield方法的作用是暫停當前線程,以便其他線程有機會執行,不過不能指定暫停的時間,並且也不能保證當前線程馬上停止。yield方法只是將Running狀態轉變為Runnable狀態
join:join方法就是通過wait方法來將線程的阻塞,如果join的線程還在執行,則將當前線程阻塞起來,直到join的線程執行完成,當前線程才能執行。不過有一點需要註意,這裏的join只調用了wait方法,卻沒有對應的notify方法,原因是Thread的start方法中做了相應的處理,所以當join的線程執行完成以後,會自動喚醒主線程繼續往下執行
5.synchronized原理
synchronized 依賴於軟件層面jvm
每個對象有一個監視器鎖(monitor)。當monitor被占用時就會處於鎖定狀態,線程執行monitorenter指令時嘗試獲取monitor的所有權,過程如下:
1、如果monitor的進入數為0,則該線程進入monitor,然後將進入數設置為1,該線程即為monitor的所有者。
2、如果線程已經占有該monitor,只是重新進入,則進入monitor的進入數加1.
3.如果其他線程已經占用了monitor,則該線程進入阻塞狀態,直到monitor的進入數為0,再重新嘗試獲取monitor的所有權。
Java SE1.6為了減少獲得鎖和釋放鎖所帶來的性能消耗,引入了“偏向鎖”和“輕量級鎖”,
6.lock原理
lock無關JVM實現的,依賴於硬件層面,
使用CLH對列(什麽前驅,尾部自旋,沒記住)實現。原生的CLH隊列是用於自旋鎖,但Doug Lea把其改造為阻塞鎖。
7.synchronized和lock區別
使用上:
synchronized 在成功完成功能或者拋出異常時,虛擬機會自動釋放線程占有的鎖;而Lock對象在發生異常時,如果沒有主動調用unLock()方法去釋放鎖,則鎖對象會一直持有,因此使用Lock時需要在finally塊中釋放鎖;
lock接口鎖可以通過多種方法來嘗試獲取鎖包括立即返回是否成功的tryLock(),以及一直嘗試獲取的lock()方法和嘗試等待指定時間長度獲取的方法,相對靈活了許多比synchronized;
寫鎖來提高系統的性能,因為讀鎖是共享鎖,即可以同時有多個線程讀取共享資源,而寫鎖則保證了對共享資源的修改只能是單線程的。
lock可以實現公平鎖
原理上:見上面
8.JUC並發包基本類
Atomic原子類分類 :
原子更新基本類型(如AtomicInteger ):CAS操作來保證操作的原子性。
原子更新數組類型(如AtomicLongArray ):CAS操作來保證操作的原子性。
原子更新引用類型(如AtomicReference):
並發容器類:
ConcurrentHashMap:分段鎖機制保證並發性
CopyOnWriteArrayList:CopyOnWriteArrayList的缺點,就是修改代價十分昂貴,每次修改都伴隨著一次的數組復制;但同時優點也十分明顯,就是在並發下不會產生任何的線程安全問題,也就是絕對的線程安全,類似讀寫分離和最終一致性(數據並不是最新)
特殊功能類:
CountDownLatch:(減計數方式)一個計數器來實現的,計數器的初始值為線程的數量。每當一個線程完成了自己的任務後,計數器的值就會減1。當計數器值到達0時,它表示所有的線程已經完成了任務,然後在閉鎖上等待的線程就可以恢復執行任務。
CyclicBarrier(加計數方式):計數達到指定值時釋放所有等待線程
Semaphore:翻譯成字面意思為 信號量,Semaphore可以控同時訪問的線程個數,通過 acquire() 獲取一個許可,如果沒有就等待,而 release() 釋放一個許可。
ThreadLocal:為每個線程提供一個獨立的變量副本
鎖類:
ReentrantLock(可重入鎖):可以有公平鎖和非公平鎖、嘗試獲得鎖(tryLock())等優點
Condition:Lock類可以創建Condition對象,Condition對象用來是線程等待和喚醒線程,需要註意的是Condition對象的喚醒的是用同一個Condition執行await方法的線程,所以也就可以實現喚醒指定類的線程
ReadWriteLock:讀讀共享,寫寫互斥,讀寫互斥
其他:
BlockQueue:同步實現的隊列
線程池類:
見上面介紹。
9.blockQueue 阻塞隊列
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
三:數據庫(這裏主要看mysql innoDB)
1.mysql引擎類別
MyISAM:不支持事務,表鎖,不支持外鍵,非聚集索引,數據文件是分離的,適合大量讀應用
InnoDB:支持事務,支持外鍵,表鎖和行鎖、聚集索引,數據文件是和索引綁在一起的,必須要有主鍵,通過主鍵索引效率很高。但是輔助索引需要兩次查詢,先查詢到主鍵,然後再通過主鍵查詢到數據。
其他:NDB和Memory(表中的數據存放在內存中)、Maria(新開發的引擎,設計目標主要是用來取代原有的MyISAM存儲引擎)
2.InnoDB表鎖和行列鎖的區別
表鎖:略
行鎖:
大體兩種:共享鎖和排它鎖
共享鎖:允許事務讀取一行數據。
排它鎖:允許事務刪除或者更新一條數據。
行鎖是通過給索引上的索引項加鎖來實現的
使用:由於InnoDB預設是Row-Level Lock,所以只有「明確」的指定主鍵,MySQL才會執行Row lock (只鎖住被選取的資料例) ,否則MySQL將會執行Table Lock (將整個資料表單給鎖住)。
3.mysql索引
對於innodb來說
使用上:主鍵索引、唯一索引、普通索引、全文索引(高版本開始支持)、組合索引
原理上:b+樹,自適應hash索引,聚集索引(主鍵默認為輔助索引,如果沒有主鍵,自動選取一個合適的列建立,存儲索引和行數據)、輔助索引(存儲所在列數據和對應聚合索引位置)
使用1:組合索引左匹配原則
使用2:
mysql EXPLAIN 命令
id: SELECT 查詢的標識符. 每個 SELECT 都會自動分配一個唯一的標識符.
select_type: SELECT 查詢的類型.
table: 查詢的是哪個表
partitions: 匹配的分區
type: join 類型
possible_keys: 此次查詢中可能選用的索引
key: 此次查詢中確切使用到的索引.
ref: 哪個字段或常數與 key 一起被使用
rows: 顯示此查詢一共掃描了多少行. 這個是一個估計值.
filtered: 表示此查詢條件所過濾的數據的百分比
extra: 額外的信息
4.索引失效常見情況
使用函數、左匹配、like,or(必須所有的or條件都必須是獨立索引),is null,等
5.事務
四大屬性ACID即事務的原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability).。
事務隔離級別:
臟讀:指一個事務讀取了另外一個事務未提交的數據。
不可重復讀:在一個事務內讀取表中的某一行數據,多次讀取結果不同
幻讀:幻讀和不可重復讀都是讀取了另一條已經提交的事務(這點就臟讀不同),所不同的是不可重復讀查詢的都是同一個數據項,而幻讀針對的是一批數據整體(比如數據的個數)。
數據庫隔離級別:
① Serializable (串行化):可避免臟讀、不可重復讀、幻讀的發生。
② Repeatable read (可重復讀):可避免臟讀、不可重復讀的發生。
③ Read committed (讀已提交):可避免臟讀的發生。
④ Read uncommitted (讀未提交):最低級別,任何情況都無法保證。
6.如何優化一條sql
第一步:理解sql業務,邏輯上是否可以優化
第二部:explain sql執行計劃,目測有沒有該走的索引沒有走
第三部:查看有無常見影響效率的錯誤,如null,列上使用函數,or不走組合索引,join之前減少join列數
第四部:增加合適的索引
第五步:還不行,嘗試限制需求(如只可以統計指定範圍數據)或者其他方式實現(如定時任務定時分析一批)
第六步:數據量超大,只可以考慮分表分庫等手段了。
四:數據結構與算法(這裏是部分,思想一樣)
1.排序(手寫部分排序算法)
冒泡排序,插入排序,快排。
冒泡:兩個循環
插入:從第二個開始,替換
快排:
2.java實現棧和隊列
棧:鏈表實現,插入頭部插入,刪除頭部刪除
隊列:鏈表實現,插入頭部插入,出隊列尾部去除
3.java遍歷二叉樹
第一個:前序遍歷(中後遍歷類似):
private void qianOut(TwoTreeDemo<Integer> headNode) {
if(headNode!=null){
System.out.print(headNode.value+",");
if(headNode.leftNode!=null){
qianOut(headNode.leftNode);
}if(headNode.rightNode!=null){
qianOut(headNode.rightNode);
}
}
}
4.鏈表常見相關算法(提示)
第一個:O(1)時間刪除指定節點:將該節點的值和next替換為下一節點的,並刪除下一節點
第二個:查找鏈表的倒數第k個節點、鏈表中間值、兩個鏈表重復處:快慢指針法(見底部附註)
private NodeDemo<Integer> getk(NodeDemo<Integer> headNode,int k) {
if(headNode==null || k<0){
return null;
}
NodeDemo oneNode = headNode;
NodeDemo tweNode = headNode;
int i = 1;
while (oneNode.nextNode != null){
oneNode = oneNode.nextNode;
if(i>=k){
tweNode = tweNode.nextNode;
}
i++;
}
if(i<k){
return null;
}
return tweNode;
}
第三個:反轉鏈表:
private void backNode(NodeDemo<Integer> headNode) {
if(headNode.nextNode == null){//如果是最後一個
this.headNode = headNode; //返回新的頭部
return ;
}else {
NodeDemo beforeNode = headNode;
backNode(headNode.nextNode);
headNode.nextNode.nextNode = beforeNode; // 反轉
headNode.nextNode = null; // 頭結點置為空
}
}
第四個:判斷鏈表有無環
1):快慢指針
2):遍歷並放入hash中判斷是否重復
五:中間件-nosql內存數據庫(redis)-經常使用哪個研究哪個
1.reids基本數據類型
String (Key-Value),Hash(Key-Value),List ,Set,zset,HyperLogLog(不常用)
2.redis持久化機制
RDB持久化是指用數據集快照的方式記錄redis數據庫的所有鍵值對。
AOF持久化是指所有的命令行記錄以redis命令請求協議的格式保存為aof文件。
3.如何保證redis和db的一致性
(弱一致性)
方案1:讀取時,先從redis中取,如果沒有則從數據庫中取出,然後放入redis中。修改刪除時,使redis中數據失效,優化點:雙刪除(寫入前後都刪除)
方案2:讀取mysql的日誌binglog
4.redis分布式鎖實現
方式一:官方提供的插件
方式二:自己手寫,註意點:使用setnx,EXPIRE 或者set四個參數;根據要鎖的資源生成key,當前事務生成value;得到鎖時設置超時時間;未得到鎖設置大概循環時間;未得到鎖判斷原來的鎖有沒有設置過期時間;釋放鎖時使用watch機制或者luna腳本
5.redis事務
Redis中的事務(transaction)是一組命令的集合。
reids事務不會回滾,只有全部執行和全部不執行兩種,部分語句執行失敗不會停止
MULTI(事務開始)EXEC(末尾) watch(觀察) unwatch(解除觀察)
6.reids過期策略
定時刪除:在設置key的過期時間的同時,為該key創建一個定時器,讓定時器在key的過期時間來臨時,對key進行刪除(基本不使用)
惰性刪除:key過期的時候不刪除,每次從數據庫獲取key的時候去檢查是否過期,若過期,則刪除,返回null。(內置策略)
定期刪除:每隔一段時間執行一次刪除(在redis.conf配置文件設置hz,1s刷新的頻率)過期key操作
7.redis key-value基本原理,如set key value流程
六:中間件-反向代理(nginx)-經常使用哪個研究哪個
1.session處理
方案一:會話保持。如使用ip_hash將某個ip定向到某個服務器
方案二:中間件session共享。如tomcat session共享
方案三:獨立節點存儲session.如session通過spring或者tomcat整合存儲到redis中
2.分發策略
輪詢(默認):每個請求按時間順序逐一分配到不同的後端服務器,如果後端服務器down掉,能自動剔除。
weight(權重):指定輪詢幾率,weight和訪問比率成正比,用於後端服務器性能不均的情況。 例如:
ip_hash(ip分):每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個後端服務器,可以解決session的問題。 例如:
fair(第三方):按後端服務器的響應時間來分配請求,響應時間短的優先分配。
七:中間件-消息隊列(activemq)-經常使用哪個研究哪個
1.activemq持久化
amq:ActiveMQ5.3之前的版本,消息存儲在一個個文件中
KahaDB:5.4版本之後KahaDB做為默認的持久化方式
JDBC:可以將消息存儲到數據庫中,例如:Mysql、SQL Server、Oracle、DB2。
LevelDB:從ActiveMQ5.8之後引進的,它和KahaDB非常相似,也是基於文件的本地數據庫儲存形式.
2.activemq消息丟失如何處理
情況一:發送到broker時消息丟失
解決:先持久到數據庫,發送成功後刪除或者標記刪除。定時任務處理
情況二:broker崩潰
解決:消息持久化
情況三:broker到消費端出問題
解決:邏輯整理使其可以重新發送(如,發送時持久化消息並置狀態為已發送,消費成功則置為已消費),當然消費要實現等冪性
3.消息重復消費問題
可能原因:發送時消息重復、投遞時消息重復
消費者的接口要實現等冪性
方法一:全局唯一ID:根據業務的操作和內容生成一個全局ID,在執行操作前先根據這個全局唯一ID是否存在,來判斷這個操作是否已經執行。
方法二:去重表,建立一個去重表,去重表中設置唯一索引,如果去重表插入成功則執行
方式三:多版本控制
4.消費順序性如何保證
方案一:保證需要排序的消息按照先後順序發送到同一個消費隊列中,並且這個隊列只有一個相應的消費者
方案二:通過業務限制,保證前消息被消費完,才可以發送後消息
八:框架類(spring springmvc mybatis)
1.springmvc流程圖
DispatcherServlet前端控制器接收發過來的請求,交給HandlerMapping處理器映射器
HandlerMapping處理器映射器,根據請求路徑找到相應的HandlerAdapter處理器適配器(處理器適配器就是那些攔截器或Controller)
HandlerAdapter處理器適配器,處理一些功能請求,返回一個ModelAndView對象(包括模型數據、邏輯視圖名)
ViewResolver視圖解析器,先根據ModelAndView中設置的View解析具體視圖
然後再將Model模型中的數據渲染到View上
2.spring ioc
3.spring aop
4.spring是如何實現事務的
四種方式:
方式一:編程式事務管理:需要手動編寫代碼,在實際開發中很少使用
方式二:聲明式事務
基於TransactionProxyFactoryBean的方式,需要為每個進行事務管理的類做相應配置
基於AspectJ的XML方式,tx標簽不需要改動類,在XML文件中配置好即可
基於註解的方式,@Transactional,配置簡單,需要在業務層類中添加註解(使用較多)
5.spring事務傳播行為
TransactionDefinition.PROPAGATION_REQUIRED:如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:創建一個新的事務,如果當前存在事務,則把當前事務掛起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式運行,如果當前存在事務,則把當前事務掛起。
TransactionDefinition.PROPAGATION_NEVER:以非事務方式運行,如果當前存在事務,則拋出異常。
TransactionDefinition.PROPAGATION_MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。
TransactionDefinition.PROPAGATION_NESTED:如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。
6.Spring的scope
默認是單例模式,即scope="singleton"。
1.singleton單例模式:全局有且僅有一個實例
2.prototype原型模式:每次獲取Bean的時候會有一個新的實例
3.request:request表示該針對每一次HTTP請求都會產生一個新的bean,同時該bean僅在當前
4.session:session作用域表示該針對每一次HTTP請求都會產生一個新的bean,同時該bean僅在當前HTTP session內有效HTTP request內有效
5.global session:global session作用域類似於標準的HTTP Session作用域,不過它僅僅在基於portlet的web應用中才有意義。Portlet規範定義了全局Session的概念,它被所有構成某個 portlet web應用的各種不同的portlet所共享。
九:java虛擬機和jmm
1.jvm(HotSpot)由哪些區域組成,每個區域的作用
方法區:線程共享的內存區域,用於存儲以被虛擬機加載的類信息、常量、靜態變量
運行時常量池:方法區的一部分,用於存放編譯期生成的各種字面量和符號引用
程序計數器:它是一塊較小的內存空間,它的作用是記錄當先線程所執行的字節碼的信號指示器。
本地方法棧:本地方法棧與虛擬機棧作用相似,後者為虛擬機執行Java方法服務,而前者為虛擬機用到的Native方法服務。
虛擬機棧(Virtual Machine Stack):每一個線程都有自己的虛擬機棧,這個棧與線程同時創建,它的生命周期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每個方法被執行的時候都會同時創建一個棧幀(StackFrame)用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。
堆(Heap)::存放對象實例
直接內存(Direct Memory):nio使用
2.java類加載流程
Java虛擬機把描述類的數據從Class文件加載到內存,並對數據進行校驗、轉換解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這就是虛擬機的加載機制。
類從被加載到虛擬機內存中開始,到卸載出內存為止,它的整個生命周期包括了:加載(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(using)、和卸載(Unloading)七個階段。其中驗證、準備和解析三個部分統稱為連接(Linking)
3.classloader
4.java垃圾回收機制
十:socket編程(看需要是否需要了解)http://www.jfox.info/java-nio-jieshao.html
1.socket
本質為實現兩個進程之間的通信
2.tcp和udp的區別
TCP:傳輸控制協議,面向連接,可靠。保證數據傳輸成功。(三次握手和四次分手)
UDP:不可靠。傳輸速度快。占系統資源少。
3.bio,nio和aio
BIO:是當發起I/O的讀或寫操作時,均為阻塞方式,直到應用程序讀到了流或者將流寫入數據。
NIO:基於事件驅動思想,常采用reactor(反應器)模式。當發起 IO請求時,應用程序是非阻塞的。當SOCKET有流可讀或寫的時候,由操作系統通知應用程序,應用程序再將流讀取到緩沖區或者寫入系統。
AIO:同樣基於事件驅動的思想,通常采用Proactor(前攝器模式)實現。在進行I/O操作時,直接調用API的read或write,這兩種方法均為異步。對於讀操作,操作系統將數據讀到緩沖區,並通知應用程序,對於寫操作,操作系統將write方法傳遞的流寫入並主動通知應用程序。它節省了NIO中遍歷事件通知隊列的代價。
4.java nio
核心:Channels,Buffers,Selectors
Channel :所有的 IO 在NIO 中都從一個Channel 開始,Channel 有點象流。 數據可以從Channel讀到Buffer中,也可以從Buffer 寫到Channel中。(FileChannel、SocketChannel、ServerSocketChannel)
Buffers:本質上是一塊用於讀寫的內存,包裝成了緩沖區對象,你可以通過allocateDirect()或者allocate()申請內存空間(allocate分配方式產生的內存開銷是在JVM中的,而allocateDirect的分配方式產生的開銷在JVM之外,以就是系統級的內存分配,使用allocateDirect尤其註意內存溢出問題),Buffer尤其需要理解三個概念,capacity、position、limit,capacity是固定大小,position是當前讀寫位置,limit是一個類似於門限的值,用於控制讀寫的最大的位置。Buffer的常用方法有clear、compact、flip等等,還有比如Buffer的靜態方法wrap等等,這些需要根據capacity、position、limit的值進行理解。,(ByteBuffer,IntBuffer,LongBuffer等)
Selector:用於檢測通道,我們通過它才知道哪個通道發生了哪個事件,所以如果需要用selector的話就需要首先進行register,然後遍歷SelectionKey對事件進行處理。它一共有SelectionKey.OP_CONNECT、SelectionKey.OP_ACCEPT、SelectionKey.OP_READ、SelectionKey.OP_WRITE四種事件類型。
5.socket編程基本流程
bio:
服務器端:
創建ServerSocket對象,綁定監聽端口
通過accept()方法監聽客戶端請求
連接建立後,通過輸入流讀取客戶端發送的請求信息
通過輸出流向客戶端發送鄉音信息
關閉相關資源
客戶端:
創建Socket對象,指明需要連接的服務器的地址和端口號
連接建立後,通過輸出流想服務器端發送請求信息
通過輸入流獲取服務器響應的信息
關閉響應資源
nio:
十一:其他
1.設計模式(知道部分即可)
設計模式大體分類:創建型模式,結構型模式,行為型模式
創建型模式:創建對象的同時隱藏創建邏輯,而不是直接使用 new 運算符直接實例化對象。
如:工廠模式,單例模式(至少會一種寫法),建造者模式,原型模式
結構型模式:關註類和對象的組合
如:
適配器模式
src類->適配器->dst類
對象適配器模式
適配器擁有src類的實例,實現dst類的接口
橋接模式
類似接口和實現類
過濾器模式
一個過濾維度寫一個過濾類,然後寫一個與類,寫一個或類
擴展時擴展維度就可以
裝飾器模式
裝飾對象接受所有客戶端的請求,並把這些請求轉發給真實的對象。這樣,就能在真實對象調用前後增加新的功能。
代理模式,
代理類和被代理類實現同一個接口
被代理類中擁有一個代理類的實例
行為型模式:關註對象之間的通信
如:責任鏈模式,叠代器模式,命令模式
責任鏈模式
類似攔截器等
命令模式:
將調用者 被調用者 被調用者的行為分開
解釋器模式:
每個語法為一個解釋器類
叠代器模式:
將集合類的查看遍歷和增刪改行為分離
附註:
1)transient:防止某個屬性被序列化
2)CAS算法:有3個操作數,內存值V,舊的預期值A,要修改的新值B。當且僅當預期值A和內存值V相同時,將內存值V修改為B,否則什麽都不做。這裏可能有ABA問題以及如何避免ABA(用版本號)
3)快慢指針法:設置兩個指針確認接受此offer
java面試常問問題及部分答案(2018)