【面試】三七互娛java遊戲開發二面準備

java的基本數據類型

int32 short16 long64 float32 double64 char16 byte8 boolean1位

說一下String

String是java中的一個類,他的底層實現是一個char數組,String一旦創建大小就不能再改變,如果要改變String的值,只能重新創建一個String類並把修改後的char數組copy到新建String中

爲什麼String不可變呢,因爲底層數組char[]被private final修飾,且沒有對外提供set方法,因此不可變

不可變的好處:不可變對象更容易被構造、測試、使用

真正不可變對象都是線程安全的

對象變化的問題得到了避免

用過哪些數據結構或者集合的類

list:

    arraylist:底層實現是數組,適合隨機查詢,線程不安全

    linkedlist:底層實現是鏈表,方便增刪,適合大量數據操作,線程不安全

    vector:和arraylist的區別是vector是線程安全的,因爲vector中的方法都被同步了,多線程無法同時訪問

set:元素唯一性

    hashset:HashSet按Hash算法來存儲集合中的元素,因此具有很好的存取和查找性能。底層數據結構是哈希表。
哈希表是一個元素爲鏈表的數組,綜合了數組與鏈表的優點。

hashSet具有以下特點:

    不能保證元素的排列順序,順序可能與添加順序不同,順序也可能發生變化;
    HashSet不是同步的;
    集合元素值可以是null;

map:

    hashmap:線程不安全,初始容量爲16,默認加載因子0.75(存儲數據達到size的0.75時擴容),擴容爲原來的兩倍,key和value都可以爲null,數據結構:數組+鏈表+紅黑樹(鏈表長度大於8時轉換爲紅黑樹,小於6時轉回爲鏈表)

    hashtable:hashtable 是線程安全的,方法是Synchronized 的,適合在多線程環境中使用,效率稍低: HashMap不是線程安全的,方法不是Synchronized的,效率稍高,初始容量爲11,擴容機制爲2倍原來大小+1,key和value都不允許爲null

    concurrenthashmap:線程安全且高效的HashMap實現,1.8後採用CAS + synchronized 來保證併發安全性

arraylist 和 linkedlist 的區別

ArrayList和LinkedList兩者都實現了List接口,但是它們之間有些不同。
(1)ArrayList是由Array所支持的基於一個索引的數據結構,所以它提供對元素的隨機訪問
(2)與ArrayList相比,在LinkedList中插入、添加和刪除一個元素會更快
(3)LinkedList比ArrayList消耗更多的內存,因爲LinkedList中的每個節點存儲了前後節點的引用

arraylist(vector)的擴容策略:

arraylist的底層實現是數組,擴容時分配更大的內存新建一個數組,釋放之前的內存,將目前的數據放入新建數組,初始容量爲10(也可以自定義指定初始容量),擴容倍數0.5(vector的擴容倍數是1)

爲什麼hashmap容量大於8時會轉換爲紅黑樹

HashMap在jdk1.8之後引入了紅黑樹的概念,表示若桶中鏈表元素超過8時,會自動轉化成紅黑樹;若桶中元素小於等於6時,樹結構還原成鏈表形式。

原因:兩個說法。。。我覺得第二個對

說法一:

  紅黑樹的平均查找長度是log(n),長度爲8,查找長度爲log(8)=3,鏈表的平均查找長度爲n/2,當長度爲8時,平均查找長度爲8/2=4,這纔有轉換成樹的必要;鏈表長度如果是小於等於6,6/2=3,雖然速度也很快的,但是轉化爲樹結構和生成樹的時間並不會太短。

還有選擇6和8的原因是:

  中間有個差值7可以防止鏈表和樹之間頻繁的轉換。假設一下,如果設計成鏈表個數超過8則鏈表轉換成樹結構,鏈表個數小於8則樹結構轉換成鏈表,如果一個HashMap不停的插入、刪除元素,鏈表個數在8左右徘徊,就會頻繁的發生樹轉鏈表、鏈表轉樹,效率會很低。

說法二:

    理想情況下,在隨機哈希代碼下,桶中的節點頻率遵循泊松分佈,文中給出了桶長度k的頻率表。由頻率表可以看出,桶的長度超過8的概率非常非常小。所以作者應該是根據概率統計而選擇了8作爲閥值。

棧和隊列的區別

棧是先進後出,棧頂進棧頂出,只能從一邊操作,遍歷時需要新開闢空間,效率更慢

隊列是先進先出,隊尾進對頭出,兩邊都有操作,隊列是基於地址指針進行遍歷,無需開闢空間,效率更快

堆和棧的區別

最主要的區別就是棧內存用來存儲局部變量和方法調用。
而堆內存用來存儲Java中的對象。無論是成員變量,局部變量,還是類變量,它們指向的對象都存儲在堆內存中。
獨有還是共享
棧內存歸屬於單個線程,每個線程都會有一個棧內存,其存儲的變量只能在其所屬線程中可見,即棧內存可以理解成線程的私有內存。
而堆內存中的對象對所有線程可見。堆內存中的對象可以被所有線程訪問。
異常錯誤
如果棧內存沒有可用的空間存儲方法調用和局部變量,JVM會拋出java.lang.StackOverFlowError。
而如果是堆內存沒有可用的空間存儲生成的對象,JVM會拋出java.lang.OutOfMemoryError。
空間大小
棧的內存要遠遠小於堆內存,如果你使用遞歸的話,那麼你的棧很快就會充滿。如果遞歸沒有及時跳出,很可能發生StackOverFlowError問題。

紅黑樹、二叉樹、平衡二叉樹、b+樹的區別

https://blog.csdn.net/wyqwilliam/article/details/82935922

二叉搜索/排序樹:左孩子<根節點<右孩子,但如果是有序數據容易退化成鏈表-->引入平衡二叉樹

平衡二叉樹:平衡二叉樹一定是二叉搜索樹,左右子樹高度相差不超過1

紅黑樹:平衡二叉樹的一種,主要用它存儲有序數據,時間複雜度是O(logN),效率非常高

B樹:多路搜索樹、一棵m階B樹是一棵平衡的m路搜索樹,非根節點所包含的關鍵字個數 j 滿足:┌m/2┐ - 1 <= j <= m - 1(m=3,則0<j<3-1);設計成多路——進一步降低樹的高度,提高搜索性能,路數越多,性能越高?不一定,如果設計成無限多路,退化成有序數組,B樹多用於文件系統和數據庫的索引,索引存儲在硬盤上,數據量大的話不一定一次能加載到內存中,就無法進行查找了,而B樹每次加載一個節點,一步步往下查找

在內存中紅黑樹效率更高,但是涉及到硬盤操作,B樹更優

B+樹基於B樹改造,數據都在葉子節點,同時葉子節點之間還加入了指針形成鏈表

B+樹在數據庫索引中用的比較多,數據庫操作可能會選取多條數據,B樹可能會做局部的中序遍歷,進行跨層訪問,效率降低,而B+樹數據都在葉子節點,不用跨層,同時有鏈表結構,只要找到首位,就能通過鏈表把所有數據取出

鎖有哪些

【1】公平鎖和非公平鎖。
公平鎖:是指按照申請鎖的順序來獲取鎖,
非公平所:線程獲取鎖的順序不一定按照申請鎖的順序來的。

【2】共享鎖和獨享鎖
獨享鎖:一次只能被一個線程所訪問
共享鎖:線程可以被多個線程所持有。
ReadWriteLock 讀鎖是共享鎖,寫鎖是獨享鎖。

【3】樂觀鎖和悲觀鎖。讀取頻繁使用樂觀鎖,寫入頻繁使用悲觀鎖
樂觀鎖:每次去拿數據的時候都認爲別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,如果發生衝突上層會不斷地retry,可以使用版本號等機制。樂觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,像數據庫如果提供類似於write_condition機制的其實都是提供的樂觀鎖。

版本號機制:一般是在數據表中加上一個數據版本號version字段,表示數據被修改的次數,當數據被修改時,version值會加一。當線程A要更新數據值時,在讀取數據的同時也會讀取version值,在提交更新時,若剛纔讀取到的version值爲當前數據庫中的version值相等時才更新,否則重試更新操作,直到更新成功。


悲觀鎖:每次去拿數據的時候都認爲別人會修改,所以每次在拿數據的時候都會上鎖(行鎖,表鎖等,讀鎖,寫鎖)

樂觀鎖和悲觀鎖往往依靠數據庫提供的鎖機制實現,數據庫鎖才能真正保證數據訪問的排他性

【4】分段鎖
1.7及之前的concurrenthashmap。併發操作就是分段鎖,其思想就是讓鎖的粒度變小。

【5】偏向鎖  是指一段同步代碼一直被一個線程所訪問,那麼該線程會自動獲取鎖。降低獲取鎖的代價
輕量級鎖
重量級鎖

【6】自旋鎖
自旋鎖

死鎖

產生條件:缺一不可

1)互斥條件(不可破壞):指進程對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個進程佔用。如果此時還有其它進程請求資源,則請求者只能等待,直至佔有資源的進程用畢釋放。

2)請求和保持條件:指進程已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程佔有,此時請求進程阻塞,但又對自己已獲得的其它資源保持不放。

3)不剝奪條件:指進程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。

4)環路等待條件:指在發生死鎖時,必然存在一個進程——資源的環形鏈,即進程集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1佔用的資源;P1正在等待P2佔用的資源,……,Pn正在等待已被P0佔用的資源。

避免死鎖:

加鎖順序
加鎖時限
死鎖檢測

mysql鎖

開銷、加鎖速度、死鎖、粒度、併發性能

  • 表鎖:開銷小,加鎖快;不會出現死鎖;鎖定力度大,發生鎖衝突概率高,併發度最低
  • 行鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度小,發生鎖衝突的概率低,併發度高
  • 頁鎖:開銷和加鎖速度介於表鎖和行鎖之間;會出現死鎖;鎖定粒度介於表鎖和行鎖之間,併發度一般

JVM模型

線程共享區域:堆、方法區

線程非共享區域:java虛擬機棧,本地方法棧,程序計數器

堆:對象實例的存放區域

方法區:常量、類信息、靜態變量、當前java程序編譯後的字節碼信息

程序計數器:可看作當前線程所執行的字節碼的行號指示器

java虛擬機棧:方法調用時會在此生成棧幀,存儲局部變量,方法出口,

本地方法棧:jvm調用的native本地方法服務

數據庫索引

底層實現是B+樹

在所有的葉子結點中增加了指向下一個葉子節點的指針

MyISAM與InnoDB兩者之間的區別

1、MyISAM:默認表類型,它是基於傳統的ISAM類型,ISAM是Indexed Sequential Access Method (有索引的順序訪問方法) 的縮寫,它是存儲記錄和文件的標準方法。不是事務安全的,而且不支持外鍵,如果執行大量的select,insert MyISAM比較適合。

2、InnoDB:支持事務安全的引擎,支持外鍵、行鎖、事務是他的最大特點。如果有大量的update和insert,建議使用InnoDB,特別是針對多個併發和QPS較高的情況。

https://www.cnblogs.com/xc-chejj/p/11245034.html

https://www.zhihu.com/question/20596402?sort=created

udp與tcp的區別

         TCP(TransmissionControl Protocol 傳輸控制協議)是一種面向連接的、可靠的、基於字節流的傳輸層通信協議。

         UDP是User Datagram Protocol,一種無連接的傳輸層協議,提供面向事務的簡單不可靠信息傳送服務。可靠性由上層應用實現,所以要實現udp可靠性傳輸,必須通過應用層來實現和控制。

TCP如何實現可靠性傳輸?

建立連接、確認機制、重傳機制、滑動窗口。

如何使用udp進行可靠傳輸

發送:包的分片、包確認、包的重發

接收:包的調序、包的序號確認

目前有如下開源程序利用udp實現了可靠的數據傳輸。分別爲RUDP、RTP、UDT。

  • 1、添加seq/ack機制,確保數據發送到對端
  • 2、添加發送和接收緩衝區,主要是用戶超時重傳。
  • 3、添加超時重傳機制。

http的報文格式

GET /admin_ui/rdx/core/images/close.png HTTP/1.1
Accept: */*
Referer: http://xxx.xxx.xxx.xxx/menu/neo
Accept-Language: en-US
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E)
Accept-Encoding: gzip, deflate
Host: xxx.xxx.xxx.xxx
Connection: Keep-Alive
Cookie: startupapp=neo; is_cisco_platform=0; rdx_pagination_size=250%20Per%20Page; SESSID=deb31b8eb9ca68a514cf55777744e339

HTTP的請求報文包括:請求行(request line)、請求頭部(header)、空行請求數據(request data) 四個部分組成。

請求行包括: 請求方法,URL(包括參數信息),協議版本這些信息(GET /admin_ui/rdx/core/images/close.png HTTP/1.1)

請求頭部(Header)是一個個的key-value值,比如

Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E)
空行(CR+LF):請求報文用空行表示header和請求數據的分隔

請求數據:GET方法沒有攜帶數據, POST方法會攜帶一個body

HTTP/1.1 200 OK
Bdpagetype: 1
Bdqid: 0xacbbb9d800005133
Cache-Control: private
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html
Cxy_all: baidu+f8b5e5b521b3644ef7f3455ea441c5d0
Date: Fri, 12 Oct 2018 06:36:28 GMT
Expires: Fri, 12 Oct 2018 06:36:26 GMT
Server: BWS/1.1
Set-Cookie: delPer=0; path=/; domain=.baidu.com
Set-Cookie: BDSVRTM=0; path=/
Set-Cookie: BD_HOME=0; path=/
Set-Cookie: H_PS_PSSID=1433_21112_18560_26350_27245_22158; path=/; domain=.baidu.com
Vary: Accept-Encoding
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked
 
<!DOCTYPE html>
<!--STATUS OK-->

HTTP的響應報文包括:狀態行,響應頭,空行,數據(響應體)

狀態行包括:HTTP版本號,狀態碼和狀態值組成。

響應頭類似請求頭,是一系列key-value值

Cache-Control: private
Content-Encoding: gzip
Server: BWS/1.1
Set-Cookie: delPer=0; path=/; domain=.baidu.com
空白行:同上,響應報文也用空白行來分隔header和數據

響應體:響應的data,本例中是一段HTML

原文鏈接:https://blog.csdn.net/zx_emily/article/details/83024065

http狀態碼

https://www.cnblogs.com/xflonga/p/9368993.html

200:成功相應

403:客戶端發送的url正確,但是服務端由於某些原因拒絕響應

404:客戶端請求的資源不存在

400:其他4開頭的狀態碼不適用時使用400,往往是服務器不理解客戶端的請求

500:這是一個通用的服務器錯誤響應。對於大多數web框架,如果在執行請求處理代碼時遇到了異常,它們就發送此響應代碼。

505:當服務器不支持客戶端試圖使用的HTTP版本時發送此響應代碼。

 

http的長連接機制

在HTTP/1.0中默認使用短連接。也就是說,客戶端和服務器每進行一次HTTP操作,就建立一次連接,任務結束就中斷連接。當客戶端瀏覽器訪問的某個HTML或其他類型的Web頁中包含有其他的Web資源(如JavaScript文件、圖像文件、CSS文件等),每遇到這樣一個Web資源,瀏覽器就會重新建立一個HTTP會話。

而從HTTP/1.1起,默認使用長連接,用以保持連接特性。使用長連接的HTTP協議,會在響應頭加入這行代碼:

Connection:keep-alive

在使用長連接的情況下,當一個網頁打開完成後,客戶端和服務器之間用於傳輸HTTP數據的TCP連接不會關閉,客戶端再次訪問這個服務器時,會繼續使用這一條已經建立的連接。Keep-Alive不會永久保持連接,它有一個保持時間,可以在不同的服務器軟件(如Apache)中設定這個時間。實現長連接需要客戶端和服務端都支持長連接。

HTTP協議的長連接和短連接,實質上是TCP協議的長連接和短連接。

快排時間複雜度

nlogn

堆排序

https://segmentfault.com/a/1190000016881385?utm_source=tag-newest

線程創建方法

------------------------繼承Thread類創建線程---------------------

1】d定義Thread類的子類,並重寫該類的run()方法,該方法的方法體就是線程需要完成的任務,run()方法也稱爲線程執行體。

2】創建Thread子類的實例,也就是創建了線程對象

3】啓動線程,即調用線程的start()方法

------------------------實現Runnable接口創建線程---------------------

1】定義Runnable接口的實現類,一樣要重寫run()方法,這個run()方法和Thread中的run()方法一樣是線程的執行體

2】創建Runnable實現類的實例,並用這個實例作爲Thread的target來創建Thread對象,這個Thread對象纔是真正的線程對象

3】第三部依然是通過調用線程對象的start()方法來啓動線程

------------------------使用Callable和Future創建線程---------------------

1】創建Callable接口的實現類,並實現call()方法,然後創建該實現類的實例(從java8開始可以直接使用Lambda表達式創建Callable對象)。

2】使用FutureTask類來包裝Callable對象,該FutureTask對象封裝了Callable對象的call()方法的返回值

3】使用FutureTask對象作爲Thread對象的target創建並啓動線程(因爲FutureTask實現了Runnable接口)

4】調用FutureTask對象的get()方法來獲得子線程執行結束後的返回值

線程池參數

https://blog.csdn.net/ye17186/article/details/89467919

四種線程池詳析

https://blog.csdn.net/qq_40033365/article/details/79951507

計算機網絡每層的協議

 

輸入baid.com到顯示網頁的整個過程

dns:url->ip

三次握手建立tcp連接

http協議發送請求

獲得資源

瀏覽器渲染

linux命令

top:查看cpu使用情況

free:查看內存使用情況

ls:查看文件目錄

pwd:查看當前路徑

mkdir:新建文件夾

ps -ef:查看進程

ps -ef | grep 進程名:查看某個進程的啓動文件路徑

rm -rf:-r:強制刪除;-f:目錄遞歸刪除

mv:移動

cp:拷貝

ifconfig:查看網絡設備信息

chmod:給予權限

wget:下載

java垃圾回收機制,使用的算法有哪些,現在商用主要使用哪種回收算法

https://www.cnblogs.com/jiangtunan/p/11025521.html

標記清除算法

  • 效率問題

  • 空間問題(標記清除後會產生大量不連續的碎片)

複製算法

  • 優點:解決碎片化問題,順序分配內存簡單高效

  • 缺點:只適用於存活率低的場景,如果極端情況下如果對象面上的對象全部存活,就要浪費一半的存儲空間。

標記整理算法

爲了解決複製算法的缺陷,充分利用內存空間,提出了標記整理算法。該算法標記階段和標記清除一樣,但是在完成標記之後,它不是直接清理可回收對象,而是將存活對象都向一端移動,然後清理掉端邊界以外的內存。 如下圖所示:

分代回收算法

如何判斷是垃圾

引用計數法

可達性分析法

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章