日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

突击笔试面试(2)

發布時間:2023/12/14 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 突击笔试面试(2) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

HTTP和HTTPS
http超文本控制協議主要在Web瀏覽器和網站服務器之間傳遞信息 HTTP協議以明文方式發送內容,所以數據不安全
https可以說成是安全版的http,即在hhtp中加入ssl層。能保證數據傳輸的安全、確認網站的真實性。http的端口是80,https是443。http是無狀態協議
SSL依靠證書來驗證服務器的身份,并為瀏覽器和服務器之間的通信加密。
SSL 證書就是遵守 SSL 協議,由受信任的數字證書頒發機構 CA,在驗證服務器身份后頒發,具有服務器身份驗證和數據傳輸加密功能。

HTTP請求過程
建立連接完畢以后客戶端會發送請求給服務端
服務端接受請求并且做出響應發送給客戶端
客戶端收到響應并且解析響應響應給客戶

1.長連接
Client方與Server方先建立通訊連接,連接建立后 不斷開, 然后再進行報文發送和接收。
2.短連接
Client方與Server每進行一次報文收發交易時才進行通訊連接,交易完畢后立即斷開連接。此種方式常用于一點對多點通訊,比如多個Client連接一個Server.

長連接與短連接的概念:前者是整個通訊過程,客戶端和服務端只用一個Socket對象,長期保持Socket的連接;后者是每次請求,都新建一個Socket,處理完一個請求就直接關閉掉Socket。
所以,其實區分長短連接就是:整個客戶和服務端的通訊過程是利用一個Socket還是多個Socket進行的。

HTTPS請求過程
客戶端發送請求到服務端
服務端返回公鑰和證書到客戶端
客戶端接收后會驗證證書的安全性,如果通過則會隨機生成一個隨機數,用公鑰對其加密,發送到服務端
服務端接受到這個加密后的隨機數后會用私鑰對其解密得到真正的隨機數,隨后用這個隨機數當做私鑰對需要發送的數據進行對稱加密
客戶端在接收到加密后的數據使用私鑰(即生成的隨機值)對數據進行解密并且解析數據呈現結果給客戶

SSL加密建立
TCP和UDP的區別
1、TCP面向連接(如打電話要先撥號建立連接);UDP是無連接的,(連接是對狀態的保持,就是在客戶端和服務器端都維護一個變量,這個變量維護現在數據傳輸的狀態,
序列號和應答號是TCP通訊特有的參數,TCP通訊利用序列號和應答號來保持和確認數據的關聯與正確性)
2、通過TCP連接傳送的數據,無差錯,不丟失,不重復,且按序到達;UDP不保證可靠交付
3、TCP面向字節流UDP是面向報文的
UDP沒有擁塞控制,因此網絡出現擁塞不會使源主機的發送速率降低(對實時應用很有用,如IP電話,實時視頻會議等)
4、每一條TCP連接只能是點到點的;UDP支持一對一,一對多,多對一和多對多的交互通信
5、TCP速度慢,UDP速度快

TCP應用場景
當對網絡通信質量有要求時,比如:整個數據要準確無誤的傳遞給對方,這往往對于一些要求可靠的應用,比如HTTP,HTTPS,FTP等傳輸文件的協議,POP,SMTP等郵件的傳輸協議。下載東西

TCP如何保證可靠性
以下是TCP提供可靠性的方式:
(1)應用數據被分割成TCP認為的最合適發送的數據塊;
(2)當TCP發出一個報文段后,就啟動一個定時器,用來等待目的端確認收到這個報文段;
若沒能及時收到這個確認,TCP發送端將重新發送這個報文段(超時重傳);
(3)TCP收到一個發自TCP連接的另一端的數據后就將發送一個確認,
不過這個確認不是立即就發送,而是要推遲幾分之一秒后才發送;
(4)TCP將保持它的首部和數據的檢驗和;(這是一個端到端的檢驗和,為了檢驗數據在傳輸過程中發生的錯誤;
若檢測到段的檢驗和有差錯,TCP將丟棄和不確認收到此報文段并希望發端可以進行超時重傳)
(5)由于TCP報文段是作為IP數據報來傳輸的,又因為IP數據報的到達可能會失序,所以TCP報文段的到達也可能會失序;
因此,有必要的話TCP會對收到的數據進行重新排序后交給應用層;
(6)因為TCP報文段是作為IP數據報來傳輸的,并且IP數據報可能會發生重復,所以TCP的接收端必須丟棄掉重復的數據;
(7)TCP提供流量控制;(因為TCP連接的每一方都有固定大小的緩沖空間,
TCP的接收端只允許另一端發送接收端緩沖區所能接納的數據,這一限制可以防止較快主機致使較慢主機的緩沖區溢出)

擁塞控制的作用:
發生原理:資源的需求>可用資源
作用:避免過多的數據注入到網絡中,導致網絡中的路由器或鏈路過載。
對比流量控制:擁塞控制是一個全局的過程,涉及到所有的主機,路由器,以及所有降低和網絡相關的所有因素。
流量控制往往指點對點通信量的控制,是端對端的問題。

TCP控制擁塞實現的方法
1.慢開始
2.擁塞避免
3.快重傳
4.快恢復
慢算法和擁塞避免:;cwnd(擁塞窗口)先成倍增加,當cwnd大于等于慢開始門限時,緩慢增加(每次增加1),
當網絡出現擁塞時,慢開始門限減小為出現擁塞時cwnd的一半,cwnd設置為1開始執行慢開始算法;
快重傳和快回復:當連續接收到三個重復確認時,慢開始門限減少為一半,然后將cwnd設置為慢開始門限,然后開始執行擁塞避免算法。

UDP 文件傳輸協議
對當前網絡通訊質量要求不高的時候,要求網絡通訊速度盡量的快,這時就使用UDP。日常生活中常見使用UDP協議: 1.QQ語音 2.QQ視頻

常見的HTTP狀態碼
1XX:通知。1XX系列響應代碼僅在與HTTP服務器溝通時使用。
2XX: 成功。2XX系列響應代碼表明操作成功了。200(“OK”)
3XX 重定向。3XX系列響應代碼表明:客戶端需要做些額外工作才能得到所需要的資源。
4XX:客戶端錯誤。這些響應代碼表明客戶端出現錯誤。不是認證信息有問題,就是表示格式或HTTP庫本身有問題。客戶端需要自行改正。404(“Not Found”) 和410(“Gone”)當客戶端所請求的URI不對應于任何資源時,發送此響應代碼
5XX 服務端錯誤。這些響應代碼表明服務器端出現錯誤。500(“Internal Server Error”)這是一個通用的服務器錯誤響應

OSI參考模型
<1> 應用層:為應用層程序提供服務。HTTP,HTTPS,FTP,POP3、SMTP
<2> 表示層:數據格式轉化,數據加密
<3> 會話層:建立、管理、維護會話
<4> 傳輸層:建立管理、維護端到端的連接 .TCP、UDP
<5> 網絡層:IP地址及路由選擇. IP,ICMP
<6>數據鏈路層:提供介質訪問和鏈路管理 ARP
<7> 物理層
TCP/IP五層模型:就是應用層、表示層、會話層合成一個應用層

cookie 和session 的區別
Cookie通過在客戶端記錄信息確定用戶身份,Session通過在服務器端記錄信息確定用戶身份。
cookie分發是通過擴展HTTP協議來實現的,服務器通過在HTTP的響應頭中加上一行特殊的指示以提示瀏覽器按照指示生成相應的cookie
經常被使用的一種技術叫做URL重寫,就是把session id直接附加在URL路徑的后面
1、cookie數據存放在客戶的瀏覽器上,session數據放在服務器上。
2、cookie不是很安全,別人可以分析存放在本地的COOKIE并進行COOKIE欺騙,考慮到安全應當使用session。
3、session會在一定時間內保存在服務器上。當訪問增多,會比較占用你服務器的性能,考慮到減輕服務器性能方面,應當使用COOKIE。
4、單個cookie保存的數據不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。

瀏覽器中輸入URL到頁面返回的全過程
第一步、瀏覽器中輸入域名www.baidu.com
第二步、域名解析 瀏覽器會把輸入的域名解析成對應的IP
瀏覽器緩存-本機的host文件-路由器緩存-本地DNS服務器-頂級域名服務器
第三步、瀏覽器與目標服務器建立TCP連接 。TCP3次握手連接
第四步、瀏覽器通過http協議向目標服務器發送請求 。瀏覽器向主機發起一個HTTP-GET方法報文請求。請求中包含訪問的URL,也就是http://www.baidu.com/ ,KeepAlive,長連接,
還有User-Agent用戶瀏覽器操作系統信息,編碼等
第五步、服務器給出響應,將指定文件發送給瀏覽器 。狀態行,響應頭,響應實體內容,,表示服務器可以響應請求,返回報文
第六步、TCP釋放鏈接 。 四次揮手
第七步、瀏覽器顯示頁面中所有文本。

三次握手是指建立一個TCP連接時,需要客戶端和服務器總共發送3個包。
第一次握手:建立連接時,客戶端發送syn包(syn=j)到服務器,并進入SYN_SENT狀態,等待服務器確認;SYN:同步標志位。
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;ACK:確認標志

為什么不能用兩次握手進行連接?
死鎖是可能發生的。比如是A機要連到B機,結果發送的連接信息由于某種原因沒有到達B機;于是,A機又發了一次,結果這次B收到了,于是就發信息回來,兩機就連接。
傳完東西后,斷開。結果這時候,原先沒有到達的連接信息突然又傳到了B機,于是B機發信息給A,然后B機就以為和A連上了,這個時候B機就在等待A傳東西過去。最后 兩個機器進入無限的等待中。。。。。

TCP的連接的拆除需要發送四個包,因此稱為四次揮手
(1) TCP客戶端發送一個FIN,用來關閉客戶到服務器的數據傳送。 FIN:結束標志
(2) 服務器收到這個FIN,它發回一個ACK,確認序號為收到的序號加1。和SYN一樣,一個FIN將占用一個序號。
(3) 服務器關閉客戶端的連接,發送一個FIN給客戶端。
(4) 客戶端發回ACK報文確認,并將確認序號設置為收到序號加1。

為什么連接的時候是三次握手,關閉的時候卻是四次握手?
因為當Server端收到Client端的SYN連接請求報文后,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。
但是關閉連接時,當Server端收到FIN報文時,很可能并不會立即關閉SOCKET,
所以只能先回復一個ACK報文,告訴Client端,“你發的FIN報文我收到了”。只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四步握手

為什么TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態
雖然按道理,四個報文都發送完畢,我們可以直接進入CLOSE狀態了,但是我們必須假象網絡是不可靠的,有可以最后一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文

get和post的區別
GET把參數包含在URL中,POST通過報文傳遞參數
get傳送的數據量較小,不能大于2KB。post傳送的數據量較大,一般被默認為不受限制
get安全性非常低,post安全性較高
GET產生一個TCP數據包;POST產生兩個TCP數據包 GET方式的請求,瀏覽器會把http header和data一并發送出去,服務器響應200,
對于POST,瀏覽器先發送header,服務器響應100 continue,瀏覽器再發送data

加密
MD5是一種單向加密,它的加密不可逆,它將任意長度的字符串,經過算法計算后生成固定長度的數據,一般為16位表示。登陸
非對稱加密:它使用了一對密鑰,公鑰和私鑰私鑰只能由一方安全保管,不能外泄,而公鑰則可以發給任何請求它的人。非對稱加密使用這對密鑰中的一個進行加密,而解密則需要另一個密鑰。RSA
比如,你向銀行請求公鑰,銀行將公鑰發給你,你使用公鑰對消息加密,那么只有私鑰的持有人–銀行才能對你的消息解密。與對稱加密不同的是,銀行不需要將私鑰通過網絡發送出去,因此安全性大大提高。
對稱加密:是最快速、最簡單的一種加密方式,加密與解密用的是同樣的密鑰。AES,DES
(1) 對稱加密加密與解密使用的是同樣的密鑰,所以速度快,但由于需要將密鑰在網絡傳輸,所以安全性不高。
(2) 非對稱加密使用了一對密鑰,公鑰與私鑰,所以安全性高,但加密與解密速度慢。
(3) 解決的辦法是將對稱加密的密鑰使用非對稱加密的公鑰進行加密,然后發送出去,接收方使用私鑰進行解密得到對稱加密的密鑰,然后雙方可以使用對稱加密來進行溝通。

海量數據處理之–哈希分治
海量的數據通過hash 映射的方法分割成相應的小塊數據
hash_map 統計。對每個小數據塊,采用trie 樹/hash_map 等統計
堆/歸并排序

進程和線程
進程是操作系統分配和管理資源的基本單位,每一個進程都有一個自己的地址空間。管道 信號量 消息隊列 共享內存 套接字
線程是進程的一部分,共享進程的地址空間,是CPU 調度的一個基本單位。 鎖機制:包括互斥鎖、條件變量、讀寫 線程間的通信目的主要是用于線程同步

線程的狀態
1、新建狀態(New):新創建了一個線程對象。
2、就緒狀態(Runnable):線程對象創建后,其它線程調用了該對象的start()方法。該狀態的線程位于可執行線程池中,變得可執行,等待獲取CPU的使用權。
3、執行狀態(Running):就緒狀態的線程獲取了CPU。執行程序代碼。
4、堵塞狀態(Blocked):堵塞態是線程由于某種原因放棄CPU使用權。臨時停止執行。直到線程進入就緒狀態,才有機會轉到執行狀態。
5、死亡狀態(Dead):線程運行狀完了或者因異常退出了run()方法,該線程結束生命周期。

線程中斷
若是我們調用線程的中斷方法,當程序即將進入或是已經進入阻塞調用的時候,那么這個中斷信號應該由InterruptedException捕獲并進行重置;
當run()方法程序段中不會出現阻塞操作的時候,這時候中斷并不會拋出異常,我們需要通過interrupted()方法進行中斷檢查和中斷標志的重置。
另外,知道IO操作和synchronized上的阻塞不可中斷也是必要的。

多線程
Runnable接口和繼承Thread類和Callable接口區別
1、java的單繼承,當繼承了Thread類,則不能繼承其他類,而實現Runnable接口可以
2、Runnable線程類是實例化一個對象o之后,通過多次new Thread(o).start();啟動多個線程,而這幾個線程屬于一個對象,對象的成員變量是同一個。
Thread每個線程啟動都對應多個對象,他們的成員變量是獨立的
3、Callable支持泛型,call() 方法支持拋出異常,有返回值

多線程同步
1、同步方法,同步代碼塊 2、volatile 3、可重入鎖 ReenreantLock 4、阻塞隊列

ThreadLocal:為每個使用該變量的線程分配一個獨立的副本。每個線程都可以獨立的改變自己的副本,而不影響其他線程的副本,從而隔離了多個線程訪問數據的沖突。
概括的說,對于多線程資源共享的問題,線程同步機制采取了時間換空間的方式,訪問串行化,對象共享化;而ThreadLocal采取了空間換時間的方式,訪問并行化,對象獨享化。
如何維護副本:在ThreadLocal類中有一個Map,Map中的鍵為線程對象,值為對應線程的變量副本。

線程池:ThreadPoolExecutor 用于創建線程池的
1、int corePoolSize:該線程池中核心線程數最大值 。線程池新建線程的時候,如果當前線程總數小于corePoolSize,則新建的是核心線程。
2、int maxi1mumPoolSize: 該線程池中線程總數最大值 線程總數 = 核心線程數 + 非核心線程數。
3、keepAliveTime:線程的最大生命周期。一個非核心線程,如果不干活(閑置狀態)的時長超過這個參數所設定的時長,就會被銷毀掉,
4、TimeUnit unit:keepAliveTime的單位
5、BlockingQueue workQueue:該線程池中的任務隊列:維護著等待執行的Runnable對象。當線程池中的線程都處于運行狀態,而此時任務數量繼續增加,則需要一個容器來容納這些任務,這個任務隊列是一個阻塞式的單端隊列。
SynchronousQueue 這個隊列接收到任務的時候,會直接提交給線程處理,而不保留它。使用這個類型隊列的時候,maximumPoolSize一般指定成Integer.MAX_VALUE,即無限大防止發生錯誤
LinkedBlockingQueue:這個隊列接收到任務的時候,如果當前線程數小于核心線程數,則新建線程(核心線程)處理任務;如果當前線程數等于核心線程數,則進入隊列等待。由于這個隊列沒有最大值限制,
即所有超過核心線程數的任務都將被添加到隊列中,這也就導致了maximumPoolSize的設定失效,因為總線程數永遠不會超過corePoolSize
ArrayBlockingQueue:可以限定隊列的長度,接收到任務的時候,如果沒有達到corePoolSize的值,則新建線程(核心線程)執行任務,如果達到了,則入隊等候,如果隊列已滿,
則新建線程(非核心線程)執行任務,又如果總線程數到了maximumPoolSize,并且隊列也滿了,則發生錯誤
DelayQueue:隊列內元素必須實現Delayed接口,這就意味著你傳進去的任務必須先實現Delayed接口。這個隊列接收到任務時,首先先入隊,只有達到了指定的延時時間,才會執行任務
6、threadFactory:定義如何啟動一個線程,可以設置線程的名稱,并且可以確定是否是后臺線程等。一般用不上。
7、handler:拒絕任務處理器。由于超出線程數量和隊列容量而對繼續增加的任務進行處理的程序
AbortPolicy策略,為java線程池默認的阻塞策略,不執行此任務,而且直接拋出一個運行時異常,
CallerRunsPolicy策略,只要線程池未關閉,該策略直接在調用者線程中運行當前被丟棄的任務。顯然這樣不會真的丟棄任務,但是,調用者線程性能可能急劇下降。
DiscardOldestPolicy策略,從隊列里面拋棄head的一個任務,并再次execute 此task
DiscardPolicy策略,直接拋棄,任務不執行,空方法

阻塞隊列
ArrayBlockingQueue是一個用數組實現的有界阻塞隊列。此隊列按照先進先出(FIFO)的原則對元素進行排序。
默認情況下不保證訪問者公平的訪問隊列,所謂公平訪問隊列是指阻塞的所有生產者線程或消費者線程,
當隊列可用時,可以按照阻塞的先后順序訪問隊列,即先阻塞的生產者線程,可以先往隊列里插入元素,先阻塞的消費者線程,可以先從隊列里獲取元素。通常情況下為了保證公平性會降低吞吐量
LinkedBlockingQueue是一個用鏈表實現的有界阻塞隊列。此隊列的默認和最大長度為Integer.MAX_VALUE。此隊列按照先進先出的原則對元素進行排序。
DelayQueue是一個支持延時獲取元素的無界阻塞隊列。隊列使用PriorityQueue來實現。
隊列中的元素必須實現Delayed接口,在創建元素時可以指定多久才能從隊列中獲取當前元素。只有在延遲期滿時才能從隊列中提取元素。
SynchronousQueue是一個不存儲元素的阻塞隊列。每一個put操作必須等待一個take操作,否則不能繼續添加元素。
SynchronousQueue可以看成是一個傳球手,負責把生產者線程處理的數據直接傳遞給消費者線程。隊列本身并不存儲任何元素,非常適合于傳遞性場景
PriorityBlockingQueue是一個支持優先級的無界隊列。默認情況下元素采取自然順序排列,也可以通過比較器comparator來指定元素的排序規則。元素按照升序排列。

數組和鏈表
數組靜態分配內存,連續,查詢速度快 O(1) 增刪慢O(n) 大小固定 不能動態擴展
鏈表動態分配內存,不連續,查詢速度慢 O(n) 增刪快O(1) 大小不固定 能動態擴展

二叉查找樹,AVL樹,B樹,B+樹,紅黑樹
二叉查找樹就是左結點小于根節點,右結點大于根節點的一種排序樹,也叫二叉搜索樹。二叉查找樹比普通樹查找更快,查找、插入、刪除的時間復雜度為O(logN)。
但是二叉查找樹有一種極端的情況,就是會變成一種線性鏈表似的結構。此時時間復雜度就變味了O(N),為了解決這種情況,出現了二叉平衡樹
平衡二叉樹全稱平衡二叉搜索樹,也叫AVL樹。左子樹和右子樹的高度差不得超過1。查找、插入、刪除的時間復雜度都為O(logN),
但是由于要維持自身的平衡,所以進行插入和刪除結點操作的時候,需要對結點進行頻繁的旋轉
AVL樹每一個節點只能存放一個元素,并且每個節點只有兩個子節點。當進行查找時,就需要多次磁盤IO,
(數據是存放在磁盤中的,每次查詢是將磁盤中的一頁數據加入內存,樹的每一層節點存放在一頁中,不同層數據存放在不同頁。)
這樣如果需要多層查詢就需要多次磁盤IO。為了解決AVL樹的這個問題,就出現了B樹
B樹也叫平衡樹,是一種多路平衡樹。每個中間節點都包含k-1個元素和k個孩子,每一個葉子節點都包含k-1個元素,所有的葉子結點都位于同一層,每個節點中的元素從小到大排列
B+樹 每個中間節點包含有k個元素 每個非葉子結點存放的元素只用于索引作用,所有數據保存在葉子結點。
因為非葉子結點中存放的元素不存放數據,所以每一層可以容納更多元素,也就是磁盤中的每一頁可以存放更多元素。這樣在查找時,磁盤IO的次數也會減少
B+樹的查找穩定,因為所有的數據都在葉子結點。每個葉子結點也通過指針指向構成了一種鏈表結構,所以遍歷數據也會簡單很多
紅黑樹是一種自平衡的二叉查找樹,它的節點的顏色為紅色和黑色。它不嚴格控制左、右子樹高度或節點數之差小于等于1
1.節點是紅色或黑色。
2.根節點是黑色。
3.每個葉子節點都是黑色的空節點(NIL節點)。
4 每個紅色節點的兩個子節點都是黑色。也就是說從每個葉子到根的所有路徑上不能有兩個連續的紅色節點)。
5.從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點。

單例模式:保證類對象在運行期,只存在一個實例 (特定場合下的需要,例如,一個系統中可以存在多個打印任務,但是只能有一個正在工作的任務)。
好處:一則,解決多線程并發訪問的問題。二則節約系統內存,提交系統運行的效率,提高系統性能。

public class Singleton4 {
// 私有構造
private Singleton4() {}

private volatile static Singleton4 single = null;// 雙重檢查 public static Singleton4 getInstance() {if (single == null) {synchronized (Singleton4.class) {if (single == null) {single = new Singleton4();}}}return single; }

}
工廠模式: 用于創建多個實例,確保每個實例都是不同的對象
工廠模式是為了解耦:把對象的創建和使用的過程分開。就是Class A 想調用 Class B ,那么A只是調用B的方法,而至于B的實例化,就交給工廠類。工廠模式可以降低代碼重復
class Child{
int age = 10;
int weight = 30;
public static Child newChild(int age, int weight) {
Child child = new Child();
child.weight = weight;
child.age = age;
return child;
}
}
原型模式(Prototype)模式的思想就是將一個對象作為原型,對其進行復制、克隆,產生一個和原對象類似的新對象
public class Prototype implements Cloneable {

public Object clone() throws CloneNotSupportedException {Prototype proto = (Prototype) super.clone();return proto; }

}
裝飾模式 指的是在不必改變原類文件和使用繼承的情況下,動態地擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。IO 流是典型的裝飾模式
裝飾設計模式: Decorator模式(別名Wrapper):動態將職責附加到對象上,
若要擴展功能,裝飾者提供了比繼承更具彈性的代替方案
當要對已有的對象進行功能增強時,可以定義類,將已有對象傳入,
基于已有對象的功能,并提供加強功能。那么自定義的該類就稱為裝飾類。
裝飾類通常會通過構造方法接收被裝飾的對象,并基于被裝飾的對象的功能,提供更強的功能
裝飾模式
class Test {
public static void main(String[] args) {
Japan japan=new Japan();

NiceJapan niceJapan=new NiceJapan(japan);niceJapan.speak(); }}class Japan{void speak() {System.out.println("你好");}}class NiceJapan {NiceJapan(Japan japan){this.japan=japan;}Japan japan;void speak() {System.out.println("點點頭");japan.speak(); System.out.println("彎彎腰");}}

策略模式(Strategy) 指對象有某個行為,但是在不同的場景中,該行為有不同的實現算法。思想(針對一組算法,將每一個算法封裝到具有共同接口的獨立的類中,使得它們可以互相替換。)
比如每個人都要“交個人所得稅”,但是“在美國交個人所得稅”和“在中國交個人所得稅”就有不同的算稅方法。
當系統能在幾種算法中快速地切換,或系統中有一些類,它們僅行為不同時,或系統中存在多重條件選擇語句時,可以考慮采用策略模式

代理模式(Proxy) 代理模式給某一個對象提供一個代理對象,并由代理對象控制對原對象的引用。通俗的來講代理模式就是我們生活中常見的中介。
作用:在某些情況下,一個客戶類不想或者不能直接引用一個委托對象,而代理類對象可以在客戶類和委托對象之間起到中介的作用,其特征是代理類和委托類實現相同的接口。
1、靜態代理
靜態代理:由程序員創建或特定工具自動生成源代碼,也就是在編譯時就已經將接口,被代理類,代理類等確定下來。在程序運行之前,代理類的.class文件就已經生成。
2.動態代理
代理類在程序運行時創建的代理方式被成為動態代理。
實現:在java的java.lang.reflect包下提供了一個Proxy類和一個InvocationHandler接口,通過這個類和這個接口可以生成JDK動態代理類和動態代理對象。

責任鏈模式是一種對象的行為模式。在責任鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。
發出這個請求的客戶端并不知道鏈上的哪一個對象最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新組織和分配責任。
Struts2 的攔截器,jsp servlet 的 Filter就是使用了責任鏈模式
優點: 1、降低耦合度。它將請求的發送者和接收者解耦。2、增強給對象指派職責的靈活性

觀察者模式(有時又被稱為模型(Model)-視圖(View)模式、源-收聽者(Listener)模式或從屬者模式) 在對象之間定義了一對多的依賴,
這樣一來,當一個對象改變狀態,依賴它的對象會收到通知并自動更新。比如有一個微信公眾號服務,不定時發布一些消息,關注公眾號就可以收到推送消息,取消關注就收不到推送消息。

冒泡排序
for(int i=0;i<x.length-1;i++ ) {
for(int j=0;j<x.length-1-i;j++) {
if(x[j]>x[j+1]) {
int temp=x[j];
x[j]=x[j+1];
x[j+1]=temp;
}
}
}
冒泡排序總的平均時間復雜度為O(n的平方) 是一種穩定排序算法

插入排序
public static int[] insertSort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
for (int j = i; j > 0; j–) {
if (arr[j] < arr[j - 1]) {
// TODO:
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
} else {
// 接下來是無用功
break;
}
}
}
return arr;
}
適用于少量數據的排序,時間復雜度為O(n^2)。是穩定的排序方法

快速排序
static void quickSort(int[] x, int low, int high) {
if (low < high) {
int m = partSourt(x, low, high);

quickSort(x, low, m - 1);quickSort(x, m + 1, high);}}static int partSourt(int[] x, int low, int high) {int mid = x[low]; // 中間的那個數while (low < high) {while (low < high && x[high] >= mid) {high--;}x[low] = x[high];while (low < high && x[low] <= mid) {low++;}x[high] = x[low];}// 把中間值放到它該放的地方x[low] = mid;return low;}

最快時間復雜度O(n的平方),平均時間復雜度O(nlogn),不穩定,占用空間

堆排序:堆是一棵順序存儲的完全二叉樹。其中每個結點的關鍵字都不大于其孩子結點的關鍵字,這樣的堆稱為小根堆。其中每個結點的關鍵字都不小于其孩子結點的關鍵字,這樣的堆稱為大根堆。
(1)根據初始數組去構造初始堆(構建一個完全二叉樹,保證所有的父結點都比它的孩子結點數值大)。

(2)每次交換第一個和最后一個元素,輸出最后一個元素(最大值),然后把剩下元素重新調整為大根堆。
當輸出完最后一個元素后,這個數組已經是按照從小到大的順序排列了。
平均、最好、最壞時間復雜度:O(nlogn),不穩定,適用于大數據量的排序

歸并排序 :該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合并,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序
平均時間復雜度O(nlogn),穩定,占用空間

二分查找
public static int binarySearch(Integer[] srcArray, int des) {
//定義初始最小、最大索引
int low = 0;
int high = srcArray.length - 1;
//確保不會出現重復查找,越界
while (low <= high) {
//計算出中間索引值
int middle = (high + low)>>>1 ;//防止溢出
if (des == srcArray[middle]) {
return middle;
//判斷下限
} else if (des < srcArray[middle]) {
high = middle - 1;
//判斷上限
} else {
low = middle + 1;
}
}
//若沒有,則返回-1
return -1;
}

IO復用,AIO,BIO,NIO,同步,異步,阻塞和非阻塞
BIO:同步阻塞:排隊等買小龍蝦
NIO:同步非阻塞:預定了小龍蝦后去干其他事情,期間自己回來看小龍蝦做好沒
AIO:異步非阻塞:預定了小龍蝦后去干其實事情,小龍蝦做好了通知我
同步:執行一個操作之后,進程觸發IO操作并等待(也就是我們說的阻塞)或者輪詢的去查看IO操作(也就是我們說的非阻塞)是否完成,等待結果,然后才繼續執行后續的操作。
異步:執行一個操作后,可以去執行其他的操作,然后等待通知再回來執行剛才沒執行完的操作。
阻塞:進程給CPU傳達一個任務之后,一直等待CPU處理完成,然后才執行后面的操作。
非阻塞:進程給CPU傳達任務后,繼續處理后續的操作,隔斷時間再來詢問之前的操作是否完成。這樣的過程其實也叫輪詢。
IO的方式通常分為幾種,同步阻塞的BIO、同步非阻塞的NIO、異步非阻塞的AIO。
同步阻塞IO:在此種方式下,用戶進程在發起一個IO操作以后,必須等待IO操作的完成,只有當真正完成了IO操作以后,用戶進程才能運行。JAVA傳統的IO模型屬于此種方式!
同步非阻塞IO:在此種方式下,用戶進程發起一個IO操作以后邊可返回做其它事情,但是用戶進程需要時不時的詢問IO操作是否就緒,這就要求用戶進程不停的去詢問,
從而引入不必要的CPU資源浪費。其中目前JAVA的NIO就屬于同步非阻塞IO。

Linux
查看當前進程: ps
執行退出: exit
查看當前路徑: pwd
它用于切換當前目錄:cd
查看文件與目錄:ls
該命令常用于分析一行的信息,若當中有我們所需要的信息,就將該行顯示出來:grep
基于查找的功能非常強大的命令:find
復制文件:cp
該命令用于查看文本文件的內容:cat
用于改變文件所屬用戶組:chgrp
用于改變文件的所有者:chown
用于改變文件的權限:chmod
哪個命令專門用來查看后臺任務? job -l
終止進程用什么命令? 帶什么參數? kill -9 pid
使用什么命令查看網絡是否連通? netstat
使用什么命令查看 ip 地址及接口信息? ifconfig
查看各類環境變量用什么命令?查看所有 env

秒殺系統設計
消息隊列,redis ,服務器集群
采用redis的分布式樂觀鎖,解決高并發下的超買超賣問題.
使用countDownLatch作為計數器,將數據四線程寫入數據庫

2.1 前端方案
靜態資源緩存:將活動頁面上的所有可以靜態的元素全部靜態化,盡量減少動態元素;編程HTML文件。通過CDN緩存靜態資源,來抗峰值。
禁止重復提交:用戶提交之后按鈕置灰,禁止重復提交
用戶限流:在某一時間段內只允許用戶提交一次請求,比如可以采取IP限流
2.2 中間代理層
可利用負載均衡(例如反響代理Nginx等)使用多個服務器并發處理請求,減小服務器壓力。
2.3 后端方案 (控制層)

對秒殺的商品利用redis緩存,對商品采用redisTemplate創建list集合,對秒殺成功的用戶用redisTemplate創建set存儲。
使用rabitMQ進行流量消峰處理,連接訂單系統處理(創建交換機和隊列并連接),通過rabitTemplate寫入消息隊列之后,訂單系統通過注解配置@rabitListener交換機和隊列消費數據寫入數據庫。

采用消息隊列緩存請求:將大流量請求寫到消息隊列緩存,利用服務器根據自己的處理能力主動到消息緩存隊列中抓取任務處理請求,
數據庫層訂閱消息減庫存,減庫存成功的請求返回秒殺成功,失敗的返回秒殺結束。
利用緩存應對寫請求:緩存也是可以應對寫請求的,可把數據庫中的庫存數據轉移到Redis緩存中,所有減庫存操作都在Redis中進行,然后再通過后臺進程把Redis中的用戶秒殺請求同步到數據庫中
2.4 數據庫層
數據庫層是最脆弱的一層,一般在應用設計時在上游就需要把請求攔截掉,數據庫層只承擔“能力范圍內”的訪問請求。所以,上面通過在服務層引入隊列和緩存,讓最底層的數據庫高枕無憂。

Jstat 這是一個比較實用的一個命令,可以觀察到classloader,compiler,gc相關信息。可以時時監控資源和性能
Jmap 得到運行java程序的內存分配的詳細情況。例如實例個數,大小等
壓力測試 使用JMeter 壓測工具
下載、安裝、進入C:/JMeter/bin下面的jmeter.bat批處理文件來啟動JMeter的可視化界面,
進入測試計劃添加線程組: 設置線程數,循環次數,添加HTTP默認請求,服務器名稱,IP,以及自己設定的攜帶參數
添加監聽器,存放測試結果:聚合報告,可以表格查詢、圖形結果、樹結果
點擊運行-》啟動。

面向對象設計七大原則
1. 單一職責原則(Single Responsibility Principle)
每一個類應該專注于做一件事情。
2. 里氏替換原則(Liskov Substitution Principle)
超類存在的地方,子類是可以替換的。
3. 依賴倒置原則(Dependence Inversion Principle)
實現盡量依賴抽象,不依賴具體實現。
4. 接口隔離原則(Interface Segregation Principle)
應當為客戶端提供盡可能小的單獨的接口,而不是提供大的總的接口。
5. 迪米特法則(Law Of Demeter)
又叫最少知識原則,一個軟件實體應當盡可能少的與其他實體發生相互作用。
6. 開閉原則(Open Close Principle)
面向擴展開放,面向修改關閉。
7. 組合/聚合復用原則(Composite/Aggregate Reuse Principle CARP)1
盡量使用合成/聚合達到復用,盡量少用繼承。原則: 一個類中有另一個類的對象。

分布式、集群、負載均衡
負載均衡:客戶端的流量首先會到達負載均衡服務器,由負載均衡服務器通過一定的調度算法將流量分發到不同的應用服務器上面,
同時負載均衡服務器也會對應用服務器做周期性的健康檢查,當發現故障節點時便動態的將節點從應用服務器集群中剔除,以此來保證應用的高可用。
負載均衡又分為四層負載均衡和七層負載均衡。四層負載均衡工作在OSI模型的傳輸層,主要工作是轉發,它在接收到客戶端的流量以后通過修改數據包的地址信息將流量轉發到應用服務器
七層負載均衡工作在OSI模型的應用層,因為它需要解析應用層流量,所以七層負載均衡在接到客戶端的流量以后,還需要一個完整的TCP/IP協議棧。
七層負載均衡會與客戶端建立一條完整的連接并將應用層的請求流量解析出來,再按照調度算法選擇一個應用服務器,并與應用服務器建立另外一條連接將請求發送過去,
因此七層負載均衡的主要工作就是代理。

Nginx使用步驟:配置Nginx.conf 寫入upstream配置服務器池,配置server監聽80端口。配置nginx負載均衡策略:在upstream中加入相應的配置語句即可
session不同步問題:比如在一臺服務器上登陸以后,再次刷新請求被送到另一臺服務器,此時用戶登錄的session為null,要求重新登陸。
解決:可以把session保存到redis中,全局保存一份,所有的服務器都去訪問redis就可以了
利用Nginx靜態資源緩存(css,js文件)減低Tomcat壓力,在Nginx.conf中配置。利用Gzip壓縮算法 Nginx打包壓縮靜態資源降低帶寬
流量防刷與反爬蟲:就是在一段時間內限制用戶的請求次數。在redis中維護一個設置過期時間的key,用戶每訪問一次加1。用SprigMVC攔截器實現

負載均衡算法:加權輪詢(Weight Round Robin)法:不同的后臺服務器可能機器的配置和當前系統的負載并不相同,因此它們的抗壓能力也不一樣。跟配置高、負載低的機器分配更高的權重,
使其能處理更多的請求,而配置低、負載高的機器,則給其分配較低的權重,降低其系統負載,加權輪詢很好的處理了這一問題,并將請求按照順序且根據權重分配給后端。

加權隨機(Weight Random)法:加權隨機法跟加權輪詢法類似,根據后臺服務器不同的配置和負載情況,配置不同的權重。不同的是,它是按照權重來隨機選取服務器的,而非順序。
源地址哈希法:
源地址哈希法的思想是根據服務消費者請求客戶端的IP地址,通過哈希函數計算得到一個哈希值,
將此哈希值和服務器列表的大小進行取模運算,得到的結果便是要訪問的服務器地址的序號。

負載均衡的實現(DNS > 數據鏈路層 > IP層 > Http層)

1.DNS域名解析負載均衡(延遲)
2.數據鏈路層負載均衡
是指在通信協議的數據鏈路層修改mac地址進行負載均衡,不修改IP地址。
3. IP負載均衡(SNAT)
即在網絡層通過修改請求目標地址進行負載均衡。
4.HTTP重定向負載均衡(少見)
5.反向代理負載均衡(nginx)
也叫應用層負載均衡(Http協議)

反向代理負載均衡(nginx) ,使用tomcat+nginx搭建服務器集群
反向代理是代理服務器的一種。客戶端的請求會先到達代理服務器,代理服務器根據算法找到一臺合適的后臺服務器,然后再將請求資源返回給客戶端,
客戶端只會得知反向代理的IP地址,而不知道在代理服務器后面的服務器簇的存在。

集群:同一個業務,部署在多個服務器上

分布式:一個業務分拆成多個子業務,或者本身就是不同的業務,部署在不同的服務器上

分布式系統的CAP理論:理論首先把分布式系統中的三個特性進行了如下歸納:
一致性(C):在分布式系統中的所有數據備份,在同一時刻是否同樣的值。(等同于所有節點訪問同一份最新的數據副本)
可用性(A):在集群中一部分節點故障后,集群整體是否還能響應客戶端的讀寫請求。(對數據更新具備高可用性)
分區容忍性(P):以實際效果而言,分區相當于對通信的時限要求。系統如果不能在時限內達成數據一致性,就意味著發生了分區的情況,必須就當前操作在C和A之間做出選擇。

BASE是Basically Available(基本可用)、Soft state(軟狀態)和Eventually consistent(最終一致性)三個短語的簡寫,
BASE是對CAP中一致性和可用性權衡的結果,其來源于對大規模互聯網系統分布式實踐的結論,
是基于CAP定理逐步演化而來的,其核心思想是即使無法做到強一致性(Strong consistency),但每個應用都可以根據自身的業務特點,采用適當的方式來使系統達到最終一致性(Eventual consistency)。

基本可用是指分布式系統在出現不可預知故障的時候,允許損失部分可用性——但請注意,這絕不等價于系統不可用。如響應時間上的損失
最終一致性強調的是系統中所有的數據副本,在經過一段時間的同步后,最終能夠達到一個一致的狀態。
因此,最終一致性的本質是需要系統保證最終數據能夠達到一致,而不需要實時保證系統數據的強一致性

分布式事務:指事務的每個操作步驟都位于不同的節點上,需要保證事務的 ACID 特性。減少庫存同時更新訂單狀態。庫存和訂單不在不同一個數據庫,因此涉及分布式事務。
解決方案:消息中間件也可稱作消息隊列 (MQ),它本質上是一個暫存轉發消息的一個中間件。在分布式應用當中,我們可以把一個業務操作轉換成一個消息,
比如支付寶的余額轉如余額寶操作,支付寶系統執行減少余額操作之后向消息系統發一個消息,余額寶系統訂閱這條消息然后進行增加賬戶金額操作。

比如:一個應用有手機 APP 端和 Web 端,如果在兩個客戶端同時進行一項操作時,那么就會導致這項操作重復進行。
分布式的CAP理論告訴我們“任何一個分布式系統都無法同時滿足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance),最多只能同時滿足兩項。
三種實現方式:基于數據庫實現分布式鎖; 基于緩存(Redis等)實現分布式鎖; 基于Zookeeper實現分布式鎖;

基于數據庫的實現方式的核心思想是:在數據庫中創建一個表,表中包含方法名等字段,并在方法名字段上創建唯一索引,
想要執行某個方法,就使用這個方法名向表中插入數據,成功插入則獲取鎖,執行完成后刪除對應的行數據釋放鎖。

基于redis的實現思想:
(1)獲取鎖的時候,使用setnx加鎖,并使用expire命令為鎖添加一個超時時間,超過該時間則自動釋放鎖,鎖的value值為一個隨機生成的UUID,通過此在釋放鎖的時候進行判斷。
(2)獲取鎖的時候還設置一個獲取的超時時間,若超過這個時間則放棄獲取鎖。
(3)釋放鎖的時候,通過UUID判斷是不是該鎖,若是該鎖,則執行delete進行鎖釋放。

redis支持的數據類型
String字符串:格式: set key value。string類型是二進制安全的
Hash(哈希)格式: hmset name key1 value1 key2 value2
List(列表)Redis 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)格式: lpush name value
Set(集合)格式: sadd name value。Redis的Set是string類型的無序集合。
zset(sorted set:有序集合)格式: zadd name score value。Redis zset 和 set 一樣也是string類型元素的集合,且不允許重復的成員。

為什么說redis能夠快速執行
(1) 絕大部分請求是純粹的內存操作(非常快速)
(2) 采用單線程,避免了不必要的上下文切換和競爭條件
(3) 非阻塞IO - IO多路復用

redis 最適合的場景
如果簡單地比較Redis與Memcached的區別,大多數都會得到以下觀點:
1 、Redis不僅僅支持簡單的k/v類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。
2 、Redis支持數據的備份,即master-slave模式的數據備份。
3 、Redis支持數據的持久化,可以將內存中的數據保持在磁盤中,重啟的時候可以再次加載進行使用。
(1)、會話緩存(Session Cache)
(2)、隊列 Reids在內存存儲引擎領域的一大優點是提供 list 和 set 操作,這使得Redis能作為一個很好的消息隊列平臺來使用。
(3)、排行榜/計數器、 Redis在內存中對數字進行遞增或遞減的操作實現的非常好。Reids在內存存儲引擎領域的一大優點是提供 list 和 set 操作,這使得Redis能作為一個很好的消息隊列平臺來使用。
(4)、發布/訂閱

redis系列之數據庫與緩存數據一致性解決方案
應該是先刪除緩存,然后在更新數據庫,如果刪除緩存失敗,那就不要更新數據庫,如果說刪除緩存成功,而更新數據庫失敗,
那查詢的時候只是從數據庫里查了舊的數據而已,這樣就能保持數據庫與緩存的一致性。

緩存失效策略(FIFO 、LRU、LFU三種算法的區別)
當緩存需要被清理時(比如空間占用已經接近臨界值了),需要使用某種淘汰算法來決定清理掉哪些數據。常用的淘汰算法有下面幾種:
FIFO:First In First Out,先進先出。判斷被存儲的時間,離目前最遠的數據優先被淘汰。
LRU:Least Recently Used,最近最少使用。判斷最近被使用的時間,目前最遠的數據優先被淘汰。
LFU:Least Frequently Used,最不經常使用。在一段時間內,數據被使用次數最少的,優先被淘汰。

不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。
什么是Redis持久化?Redis有哪幾種持久化方式?優缺點是什么?
持久化就是把內存的數據寫到磁盤中去,防止服務宕機了內存數據丟失。Redis 提供了兩種持久化方式:RDB(默認) 和AOF
RDB就是將數據庫中所有的數據保存到硬盤當中,以RDB文件的形式存在,這是一個非常耗時、耗資源的操作,因此服務器需要隔一段時間才創建新的RDB文件。這使得服務器意外停機時會丟失大量數據
AOF將每個修改了數據庫的命令寫入到AOF文件末尾,再啟動服務器的時候重新執行這些命令,就可以還原數據庫中的數據。
因為寫入緩沖區的存在,AOF的安全性在于緩沖區的命令何時能被寫入到磁盤里,通過設置appendfsync配置選項解決。AOF冗余命令會很多。通過AOF的重寫

redis主從復制實現
master服務器會開啟一個后臺進程用于將redis中的數據生成一個rdb文件,與此同時,服務器會緩存所有接收到的來自客戶端的寫命令(包含增、刪、改),當后臺保存進程
處理完畢后,會將該rdb文件傳遞給slave服務器,而slave服務器會將rdb文件保存在磁盤并通過讀取該文件將數據加載到內存,在此之后master服務器會將在此期間緩存的
命令通過redis傳輸協議發送給slave服務器,然后slave服務器將這些命令依次作用于自己本地的數據集上最終達到數據的一致性。

Redis 的復制功能允許用戶根據一個 Redis 服務器來創建任意多個該服務器的復制品,其中被復制的服務器為主服務器(master),而通過復制創建出來的服務器復制品則為從服務器(slave)。
只要主從服務器之間的網絡連接正常,主從服務器兩者會具有相同的數據,主服務器就會一直將發生在自己身上的數據更新同步 給從服務器,從而一直保證主從服務器的數據相同。
降低 master 讀壓力在轉交從庫

Redis sentinel(哨兵) 是一個分布式系統中監控 redis 主從服務器,并在主服務器下線時自動進行故障轉移

總結

以上是生活随笔為你收集整理的突击笔试面试(2)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。