
京東總部的位置有點(diǎn)捉急,周圍荒蕪人煙,位于一片農(nóng)田之中,2016年末,劉強(qiáng)東開始將京東定義為一個技術(shù)型驅(qū)動的公司,開始打造眾多的技術(shù)團(tuán)隊(duì),技術(shù)氛圍不錯,但是面試官有些木訥。。。
面試題目
1. 多線程:executor原理 線程池 全解
Executor,Executors,ExecutorService,CompletionService,F(xiàn)uture,Callable
- Executors類,提供了一系列工廠方法用于創(chuàng)先線程池,返回的線程池都實(shí)現(xiàn)了ExecutorService接口。
-
public static ExecutorService newFixedThreadPool(int nThreads)
創(chuàng)建固定數(shù)目線程的線程池。 -
public static ExecutorService newCachedThreadPool()
創(chuàng)建一個可緩存的線程池,調(diào)用execute 將重用以前構(gòu)造的線程(如果線程可用)。如果現(xiàn)有線程沒有可用的,則創(chuàng)建一個新線程并添加到池中。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程。 -
public static ExecutorService newSingleThreadExecutor()
創(chuàng)建一個單線程化的Executor。 -
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
創(chuàng)建一個支持定時及周期性的任務(wù)執(zhí)行的線程池,多數(shù)情況下可用來替代Timer類。
-
ExecutorService與生命周期
-
ExecutorService擴(kuò)展了Executor并添加了一些生命周期管理的方法。 - 一個
Executor的生命周期有三種狀態(tài),運(yùn)行 ,關(guān)閉 ,終止 。Executor創(chuàng)建時處于運(yùn)行狀態(tài)。當(dāng)調(diào)用ExecutorService.shutdown()后,處于關(guān)閉狀態(tài),isShutdown()方法返回true。這時,不應(yīng)該再想Executor中添加任務(wù),所有已添加的任務(wù)執(zhí)行完畢后,Executor處于終止?fàn)顟B(tài),isTerminated()返回true。 - 如果
Executor處于關(guān)閉狀態(tài),往Executor提交任務(wù)會拋出unchecked exception RejectedExecutionException。
- 使用
Callable,Future返回結(jié)果
-
Future<V>代表一個異步執(zhí)行的操作,通過get()方法可以獲得操作的結(jié)果,如果異步操作還沒有完成,則,get()會使當(dāng)前線程阻塞。FutureTask<V>實(shí)現(xiàn)了Future<V>和Runable<V>。Callable代表一個有返回值得操作。
-
CompletionService
在剛在的例子中,getResult()方法的實(shí)現(xiàn)過程中,迭代了FutureTask的數(shù)組,如果任務(wù)還沒有完成則當(dāng)前線程會阻塞,如果我們希望任意字任務(wù)完成后就把其結(jié)果加到result中,而不用依次等待每個任務(wù)完成,可以使CompletionService。生產(chǎn)者submit()執(zhí)行的任務(wù)。使用者take()已完成的任務(wù),并按照完成這些任務(wù)的順序處理它們的結(jié)果 。也就是調(diào)用CompletionService的take方法是,會返回按完成順序放回任務(wù)的結(jié)果,CompletionService內(nèi)部維護(hù)了一個阻塞隊(duì)列BlockingQueue,如果沒有任務(wù)完成,take()方法也會阻塞。修改剛才的例子使用CompletionService:
2. hashmap實(shí)現(xiàn)原理,hashtable和hashmap區(qū)別,為什么hashmap效率高不安全,concurrenthashmap 為什么線程安全,怎樣實(shí)現(xiàn)的.
在java編程語言中,最基本的結(jié)構(gòu)就是兩種,一個是數(shù)組,另外一個是模擬指針(引用),所有的數(shù)據(jù)結(jié)構(gòu)都可以用這兩個基本結(jié)構(gòu)來構(gòu)造的,HashMap也不例外。HashMap實(shí)際上是一個“鏈表散列”的數(shù)據(jù)結(jié)構(gòu),即數(shù)組和鏈表的結(jié)合體。
HashMap底層就是一個數(shù)組結(jié)構(gòu),數(shù)組中的每一項(xiàng)又是一個鏈表。當(dāng)新建一個HashMap的時候,就會初始化一個數(shù)組。
詳細(xì)介紹:
hashmap原理全解
hashtable原理全解
3. 手寫單例模式示例,單鏈表倒序排列
單例模式的幾種寫法:詳解點(diǎn)擊:單例模式的七種寫法
//寫法一:懶加載,線程不安全
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//寫法二:懶加載,線程安全
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//寫法三:不能懶加載
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
//寫發(fā)四:寫法三的變種
public class Singleton {
private Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton (){}
public static Singleton getInstance() {
return this.instance;
}
}
//寫法五:靜態(tài)內(nèi)部類
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
//寫法六:雙重校驗(yàn)
public class Singleton {
private volatile static Singleton singleton; //保證變量值統(tǒng)一
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
單鏈表倒序排列
/**
* java 實(shí)現(xiàn)單鏈表的逆序
* @author Administrator
*
*/
public class SingleLinkedReverse {
//定義單鏈表,每個節(jié)點(diǎn)包含數(shù)據(jù)和下一個節(jié)點(diǎn)的地址
class Node {
int data;
Node next;
public Node(int data) {
this.data = data;
}
}
public static void main(String[] args) {
SingleLinkedReverse slr = new SingleLinkedReverse();
//定義兩個鏈表
Node head, tail;
//新建一個鏈表頭結(jié)點(diǎn)
head = tail = slr.new Node(0);
//新建一個長度為10的鏈表tail
for (int i = 1; i < 10; i++) {
Node p = slr.new Node(i);
tail.next = p;
tail = p;
}
//tail返回到頭節(jié)點(diǎn)0 此時head在頭結(jié)點(diǎn)
tail = head;
//循環(huán)鏈表
while (tail != null) {
System.out.print(tail.data + " ");
tail = tail.next;
}
head = reverse(head);
while (head != null) {
System.out.print(head.data + " ");
head = head.next;
}
}
/* 核心算法
前后交換位置
*/
private static Node reverse(Node head) {
Node p1, p2 = null;
p1 = head;
while (head.next != null) {
p2 = head.next;
head.next = p2.next;
p2.next = p1;
p1 = p2;
}
return p2;
}
}
4. 接口和抽象類區(qū)別,特點(diǎn) 答案全解
- 抽象類和接口都不能直接實(shí)例化,如果要實(shí)例化,抽象類變量必須指向?qū)崿F(xiàn)所有抽象方法的子類對象,接口變量必須指向?qū)崿F(xiàn)所有接口方法的類對象。
- 抽象類要被子類繼承,接口要被類實(shí)現(xiàn)。
- 接口只能做方法申明,抽象類中可以做方法申明,也可以做方法實(shí)現(xiàn)
- 接口里定義的變量只能是公共的靜態(tài)的常量,抽象類中的變量是普通變量。
- 抽象類里的抽象方法必須全部被子類所實(shí)現(xiàn),如果子類不能全部實(shí)現(xiàn)父類抽象方法,那么該子類只能是抽象類。同樣,一個實(shí)現(xiàn)接口的時候,如不能全部實(shí)現(xiàn)接口方法,那么該類也只能為抽象類。
- 抽象方法只能申明,不能實(shí)現(xiàn),接口是設(shè)計(jì)的結(jié)果 ,抽象類是重構(gòu)的結(jié)果
- 抽象類里可以沒有抽象方法
- 如果一個類里有抽象方法,那么這個類只能是抽象類
- 抽象方法要被實(shí)現(xiàn),所以不能是靜態(tài)的,也不能是私有的。
- 接口可繼承接口,并可多繼承接口,但類只能單根繼承。
5. static 特點(diǎn) 執(zhí)行順序
父類的 static 語句和 static 成員變量
子類的 static 語句和 static 成員變量
父類的 非 static 語句塊和 非 static 成員變量
父類的構(gòu)造方法
子類的 非 static 語句塊和 非 static 成員變量
子類的構(gòu)造方法
6. sql的執(zhí)行順序
SQL Select語句完整的執(zhí)行順序:
- from子句組裝來自不同數(shù)據(jù)源的數(shù)據(jù);
- where子句基于指定的條件對記錄行進(jìn)行篩選;
- group by子句將數(shù)據(jù)劃分為多個分組;
- 使用聚集函數(shù)進(jìn)行計(jì)算;
- 使用having子句篩選分組;
- 計(jì)算所有的表達(dá)式;
- 使用order by對結(jié)果集進(jìn)行排序。
- select 集合輸出。
7. having
在 SQL 中增加 HAVING 子句原因是,WHERE 關(guān)鍵字無法與合計(jì)函數(shù)一起使用。
SELECT Customer,SUM(OrderPrice) FROM Orders
WHERE Customer='Bush' OR Customer='Adams'
GROUP BY Customer
HAVING SUM(OrderPrice)>1500
8. innodb myisam的區(qū)別 和原理 答案全解
兩種類型最主要的差別就是Innodb 支持事務(wù)處理與外鍵和行級鎖。而MyISAM不支持.所以MyISAM往往就容易被人認(rèn)為只適合在小項(xiàng)目中使用。
作為使用MySQL的用戶角度出發(fā),Innodb和MyISAM都是比較喜歡的,如果數(shù)據(jù)庫平臺要達(dá)到需求:99.9%的穩(wěn)定性,方便的擴(kuò)展性和高可用性來說的話,MyISAM絕對是首選。
9. arraylist linkedlist區(qū)別
- 大概的區(qū)別
- ArrayList是實(shí)現(xiàn)了基于動態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu),LinkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu)。
- 對于隨機(jī)訪問get和set,ArrayList覺得優(yōu)于LinkedList,因?yàn)長inkedList要移動指針。
- 對于新增和刪除操作add和remove,LinedList比較占優(yōu)勢,因?yàn)锳rrayList要移動數(shù)據(jù)。
- ArrayList和LinkedList在性能上各有優(yōu)缺點(diǎn),都有各自所適用的地方,總的說來可以描述如下:
對ArrayList和LinkedList而言,在列表末尾增加一個元素所花的開銷都是固定的。對ArrayList而言,主要是在內(nèi)部數(shù)組中增加一項(xiàng),指向所添加的元素,偶爾可能會導(dǎo)致對數(shù)組重新進(jìn)行分配;而對LinkedList而言,這個開銷是統(tǒng)一的,分配一個內(nèi)部Entry對象。
在ArrayList的中間插入或刪除一個元素意味著這個列表中剩余的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。
LinkedList不支持高效的隨機(jī)元素訪問。
ArrayList的空間浪費(fèi)主要體現(xiàn)在在list列表的結(jié)尾預(yù)留一定的容量空間,而LinkedList的空間花費(fèi)則體現(xiàn)在它的每一個元素都需要消耗相當(dāng)?shù)目臻g
可以這樣說:當(dāng)操作是在一列數(shù)據(jù)的后面添加數(shù)據(jù)而不是在前面或中間,并且需要隨機(jī)地訪問其中的元素時,使用ArrayList會提供比較好的性能;當(dāng)你的操作是在一列數(shù)據(jù)的前面或中間添加或刪除數(shù)據(jù),并且按照順序訪問其中的元素時,就應(yīng)該使用LinkedList了
10. 基本請求類型
HTTP協(xié)議中共定義了八種方法或者叫“動作”來表明對Request-URI指定的資源的 不同操作方式,具體介紹如下:
OPTIONS:返回服務(wù)器針對特定資源所支持的HTTP請求方法。也可以利用向Web服務(wù)器發(fā)送'*'的請求來測試服務(wù)器的功能性。
HEAD:向服務(wù)器索要與GET請求相一致的響應(yīng),只不過響應(yīng)體將不會被返回。這一方法可以在不必傳輸整個響應(yīng)內(nèi)容的情況下,就可以獲取包含在響應(yīng)消息頭中的元信息。
GET:向特定的資源發(fā)出請求。
POST:向指定資源提交數(shù)據(jù)進(jìn)行處理請求(例如提交表單或者上傳文件)。數(shù)據(jù)被包含在請求體中。POST請求可能會導(dǎo)致新的資源的創(chuàng)建和/或已有資源的修改。
PUT:向指定資源位置上傳其最新內(nèi)容。
DELETE:請求服務(wù)器刪除Request-URI所標(biāo)識的資源。
TRACE:回顯服務(wù)器收到的請求,主要用于測試或診斷。
CONNECT:HTTP/1.1協(xié)議中預(yù)留給能夠?qū)⑦B接改為管道方式的代理服務(wù)器。
11. 響應(yīng)狀態(tài)碼
全解
301和302的區(qū)別
- 302重定向是暫時的重定向,搜索引擎會抓取新的內(nèi)容而保留舊的網(wǎng)址。因?yàn)榉?wù)器返回302代碼,搜索引擎認(rèn)為新的網(wǎng)址只是暫時的。 SEO 302好于301,但容易被劫持。
- 301重定向是永久的重定向,搜索引擎在抓取新內(nèi)容的同時也將舊的網(wǎng)址替換為重定向之后的網(wǎng)址。不會發(fā)生url劫持
12. 微服務(wù)什么概念
微服務(wù)是一項(xiàng)在云中部署應(yīng)用和服務(wù)的新技術(shù)。大部分圍繞微服務(wù)的爭論都集中在容器或其他技術(shù)是否能很好的實(shí)施微服務(wù),而紅帽說API應(yīng)該是重點(diǎn)。
WiKi