前段時間去了一家互聯網公司面試,感受被虐的挺慘的.主要緣由仍是本身對jdk不是很是熟悉,面試官沒有讓本身去寫代碼實現,也沒有考數據結構和算法,只是讓說而已.我以爲程序員不是靠說來證實本身,就像那句名言:talk is cheap,show me the code.還有就是和麪試官不是很談得來,就是沒有緣分.好了,如今總結一下面試的問題,而後寫下關於這些問題的答案.
java
問題:程序員
1.畫出項目流程圖面試
我畫了,可是面試官說畫的比較簡單,要求像程序的流程圖同樣,輸入時什麼,輸出是什麼.其實我在公司作的項目是財務部分, 公司 主要追尋敏捷開發,文檔太少了,幾乎等於沒有,咱們都是先問下同事關於業務部分,而後直接看代碼.並且這個部分的業務很是複雜,沒那麼簡單就能畫出,畫出來也須要很是多的時間.
算法
2.volatile關鍵字做用
數組
在Jvm內存中有一塊是虛擬機棧,每一個線程運行的時候都會有本身的棧,線程棧中保存了一份線程變量的備份,是從主存中複製來的,這樣在取出來以後的操做中沒法保證主存中的數據有沒有在線程操做的過程當中發生了改變.若是對變量加了volatile修飾,變量每次在使用的時候會從主存中去取,可是這仍是會產生併發的問題.因此仍是建議使用sychonized比較安全
安全
3.HashMap在多線程的狀況下會不會有問題.
數據結構
最容易讓人想到的就是髒數據,其次就是循環的問題.多線程
public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; // 標記1 addEntry(hash, key, value, i); return null; }
void addEntry(int hash, K key, V value, int bucketIndex) { if ((size >= threshold) && (null != table[bucketIndex])) { resize(2 * table.length); hash = (null != key) ? hash(key) : 0; bucketIndex = indexFor(hash, table.length); } createEntry(hash, key, value, bucketIndex); }
void createEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<>(hash, key, value, e); //標記2 size++; }
在標記1這個地方假設兩個線程都PUT同一個KEY ,A線程到了這裏,而後切到B線程,B線程也到了標記1這裏,而後A進入到addEntry方法中這時候, table數組相應的位置放的就是put進來的Key Value的Entry,一樣B線程進入到addEntry就會也生成一個相同key和value的Entry 他的next指向以前A線程建立的Entry,這裏就產生了髒數據.
併發
3.Hashtable 和CocurrentHashMap區別
jvm
public synchronized V put(K key, V value){ ... } public synchronized V get(Object key){ ... }
可見Hashtable幾乎對全部的方法上面讀加了synchronized關鍵字,等同於鎖住了整個Map表,同一時刻只能有一個線程操做同一個Hashtable對象中被sychonized修飾的方法,效率大大下降.ConcurrentHashMap東西太多了.好多地方看不懂,大概就是分了多個Segment每一個Segment裏面裝的是Entry數組就等於Hashtable,這樣操做的粒度就小了好多.在讀的時候幾乎能夠實現全併發,寫的時候只是鎖對應的Segment,而非整個Segment數組
4.Thread.sleep(),Object.await(),Object.notify(),Thread.yeild(),Object.join()的區別,
Thread.sleep(100)是當前線程不讓出系統資源的狀況下去睡覺,並且不會釋放對象鎖.Object.wait()是在同步控制塊或者方法中使用的,表示被鎖的對象進行釋放,而,notify是隨機喚醒以前在這個對象上進行wait()的線程.而notifyAll是喚醒全部在這個對象wait()的線程,而後由線程去爭搶對象鎖,由於這些線程都在sychronized中.yeild()是在不釋放對象鎖的狀況下進入就緒隊列與相同及以上優先級的線程從新競爭cpu,有可能下次仍是調用yeild的線程獲取到cpu.Thread.join()開啓一個子線程,可是必需要等待子線程執行完成以後再執行Thread.join()以後的代碼.
5.Jvm在何時回收,回收算法,jvm內存.
Jvm內存區域主要分紅,堆,虛擬機棧,本地方法棧,方法區,程序計數器.
程序計數器:是線程私有的,指向的是當前線程執行的字節碼指令的地址.若是是本地方法則爲空.
虛擬機棧:線程進入某個方法的時候建立棧幀,用於存放局部變量等信息. 本地方法棧用於本地方法
方法區:也被成爲永代區,這是全部線程共享的區域,存放了類的基本信息,靜態變量等,裏面還有的變量池,變量池主要存放的是運行前就肯定的對象,能在程序運行時進行擴展.
回收算法主要包括,標記清除,標記整理,複製,分代. 通常狀況下使用分代分紅新生代和老年代,新生代使用複製算法,老年代是用標記整理算法.