ymj小姐姐的饋贈筆記

 

 

 

1. 怎樣判斷一個對象是否線程安全?

(1) 該對象是否會被多個線程訪問修改

假如對象會被多個線程訪問,例如各種的Context或Factory

(2) 注意靜態變量

由於靜態變量是屬於該類和該類下所有對象共享,可以直接通過類名訪問和修改

(3)  改變對象內部狀態的方法調用.

當一個對象的屬性會被多個線程修改時,需要進行同步操作.但並不代表不提供某屬性的setter方法就可以萬事安心.而真正需要關注的是,哪些內部方法的調用或對外公開的方法調用會導致對象內部屬性(狀態)的改變

(3) 單例

單例由於是全局唯一,所以單例對象會被所有線程所訪問,而單例中的屬性若允許進行修改,則會引發線程安全問題.當對象在Spring管理下默認是Singleton,當我們在三層架構開發下.在DAO或Service中聲明全局變量並對其進行操作,同樣會引發線程安全問題。

2. 什麼時候數據庫語句提交?什麼時候回滾?

執行語句中途發生錯誤則回滾到上次系統正確的狀態,一般數據庫用日誌方式控制回滾。

3. Servlet是單例還是多例?

Servlet是單例的。

Servlet容器默認是採用單實例多線程的方式處理多個請求的:

1.當web服務器啓動的時候(或客戶端發送請求到服務器時),Servlet就被加載並實例化(只存在一個Servlet實例);

2.容器初始化化Servlet主要就是讀取配置文件(例如tomcat,可以通過servlet.xml的<Connector>設置線程池中線程數目,初始化線程池通過web.xml,初始化每個參數值等等。

3.當請求到達時,Servlet容器通過調度線程(Dispatchaer Thread) 調度它管理下線程池中等待執行的線程(Worker Thread)給請求者;

4.線程執行Servlet的service方法;

5.請求結束,放回線程池,等待被調用;

JSP:當客戶端第一次請求某一個JSP文件時,服務端把該JSP編譯成一個CLASS文件,並創建一個該類的實例,然後創建一個線程處理CLIENT端的請求。如果有多個客戶端同時請求該JSP文件,則服務端會創建多個線程。每個客戶端請求對應一個線程。

均不是線程安全的

4. 數據庫連接collection

5. 使用MongoDB,必須首先在MongoDB中創建 Database 和 Collection。Database是相互獨立的,每個Database都有自己的Collections,不同的database中,可以存在名字相同的collection,但是Database不是物理存儲單位,MongoDB以Collection爲物理存儲單位,每個collection都有自己的數據文件和index文件,這些文件以 .wt 結尾。 

6. 先從服務器端說起。服務器端先初始化Socket,然後與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待客戶端連接。在這時如果有個客戶端初始化一個Socket,然後連接服務器(connect),如果連接成功,這時客戶端與服務器端的連接就建立了。客戶端發送數據請求,服務器端接收請求並處理請求,然後把迴應數據發送給客戶端,客戶端讀取數據,最後關閉連接,一次交互結束。

http(超文本傳輸協議)是一個基於請求與響應模式的、無狀態的、應用層的協議,常基於TCP的連接方式。HTTP允許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type加以標記。

1. B/S模式(Browser/Server)

Browser指的是Web瀏覽器,極少數事務邏輯在前端實現,但主要事務邏輯在服務器端實現,Browser客戶端,WebApp服務器端和DB端構成所謂的三層架構。

B/S架構中,顯示邏輯交給了Web瀏覽器,事務處理邏輯在放在了WebApp上,這樣就避免了龐大的胖客戶端,減少了客戶端的壓力。因爲客戶端包含的邏輯很少,因此也被成爲瘦客戶端。

優點:客戶端無需安裝,有Web瀏覽器即可。BS架構可以直接放在廣域網上,通過一定的權限控制實現多客戶訪問的目的,交互性較強。BS架構無需升級多個客戶端,升級服務器即可。

缺點:在跨瀏覽器上,BS架構不盡如人意。在速度和安全性上需要花費巨大的設計成本。客戶端服務器端的交互是請求-響應模式,通常需要刷新頁面,在Ajax風行後此問題得到了一定程度的緩解。

相對於C/S,B/S具有如下優勢:

1、分佈性:可以隨時進行查詢、瀏覽等業務

2、業務擴展方便:增加網頁即可增加服務器功能

3、維護簡單方便:改變網頁,即可實現所有用戶同步更新

4、開發簡單,共享性強,成本低,數據可以持久存儲在雲端而不必擔心數據的丟失。

 

2. C/S模式(client/server)

其客戶端包含一個或多個在用戶的電腦上運行的程序,而服務器端有兩種,一種是數據庫服務器端,客戶端通過數據庫連接訪問服務器端的數據;另一種是Socket服務器端,服務器端的程序通過Socket與客戶端的程序通信。

C/S 架構也可以看做是胖客戶端架構。因爲客戶端需要實現絕大多數的業務邏輯和界面展示。這種架構中,作爲客戶端的部分需要承受很大的壓力,因爲顯示邏輯和事務處理都包含在其中,通過與數據庫的交互(通常是SQL或存儲過程的實現)來達到持久化數據,以此滿足實際項目的需要。

優點: C/S架構的界面和操作可以很豐富。安全性能可以很容易保證,實現多層認證也不難。由於只有一層交互,因此響應速度較快。

缺點:適用面窄,通常用於局域網中。用戶羣固定。由於程序需要安裝纔可使用,因此不適合面向一些不可知的用戶。維護成本高,發生一次升級,則所有客戶端的程序都需要改變。

1. 如何設計一個秒殺系統:前端(限制請求次數,限制同一IP的點擊次數,限制一定數量的請求有效)後端(servlet單例多線程,請求放入阻塞隊列,保證可靠。)

2. 線程的次序執行,join方法。

3. 分佈式框架,服務器

分佈式和集羣(集羣是個物理形態,分佈式是個工作方式)

分佈式:一個業務分拆多個子業務,部署在不同的服務器上

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

例:小飯店原來只有一個廚師,切菜洗菜備料炒菜全乾。後來客人多了,廚房一個廚師忙不過來,又請了個廚師,兩個廚師都能炒一樣的菜,這兩個廚師的關係是集羣。爲了讓廚師專心炒菜,把菜做到極致,又請了個配菜師負責切菜,備菜,備料,廚師和配菜師的關係是分佈式,一個配菜師也忙不過來了,又請了個配菜師,兩個配菜師關係是集羣。

負載均衡集羣:集羣中所有的節點都處於活動狀態,它們分攤系統的工作負載。這種集羣可以在接到請求時,檢查接受請求較少,不繁忙的服務器,並把請求轉到這些服務器上。一般Web服務器集羣、數據庫集羣和應用服務器集羣都屬於這種類型。

4. Cookie和session區別,session存儲在服務器上,cookie存放在瀏覽器上(客戶端),cookie怎樣去連接session?

第一次訪問服務器,會生成一個session;(session在用戶第一次訪問服務器時創建,只有訪問jsp和servlet時纔會創建,只訪問HTML,Image等靜態資源並不會創建session)

Response會返回一個sessionID,存放在會話cookie

cookie目的可以跟蹤會話,也可以保存用戶喜好或者保存用戶名密碼(將域名對應的cookie保存到硬盤中,下次訪問的時候瀏覽器查找保存在硬盤中的與該域名對應的cookie填充),session用來跟蹤會話。

      第一次訪問一個網頁。當客戶端發送請求後,服務端會建立一個針對此請求發出客戶的session對象,而且每個session都會有一個sessionID。服務端會自動將這個sessionID作爲一個cookie附加到response上返回給客戶端,這個cookie存放在瀏覽器內存中。我們每次對此網頁發送的request都會附帶着這個cookie,服務端收到這個請求後會都去cookie中取得這個sessionID,然後查詢服務端是否存在一個對應此ID的session對象。如果有,可以直接使用此session;如果沒有,則會新建一個。當瀏覽器關閉後,其所佔的內存就會是放掉,cookie自然也就被清除了,此時我們不再保存有這個sessionID。所以再打開瀏覽器訪問同一個頁面時,由於沒有sessionID,也就查不到對應的session對象,此時重新創建一個新的session對象。

5. Hashmap和hashtable區別?

Entry對象唯一表示一個鍵值對,有四個屬性:key,value,hash,entry(指向鏈表中下一個entry對象)

hashMap支持null鍵和null值,hashtable不可以。

hashMap(默認大小16,2*n擴容,然後重新計算HashMap中每個元素在數組中的位置)非線程安全,hashTable(默認11,2*n+1擴容)線程安全。

6. 用什麼工具和方法分析線程問題。

VisualVM:監控應用程序的性能和內存佔用情況、監控應用程序的線程、進行線程轉儲(Thread Dump)或堆轉儲(Heap Dump)、跟蹤內存泄漏、監控垃圾回收器、執行內存和CPU分析,保存快照以便脫機分析應用程序。

包含遠程監控Jboos服務;netstat -a | grep -i 2899 命令查看端口占有情況

7、多線程操作字符串緩衝區下大量數據用Stringbuffer,stringbuffer的append操作線程安全;單線程操作字符串緩衝區下大量數據,可使用StingBuilder獲取更好的性能。

Jvm對String字符串的操作效率低,String是不可變類,每當用String操作字符串時,實際上是在不斷的創建新的對象,把操作後的值放到新的對象裏,把引用的指針指向新的對象,而原來的對象就會變爲垃圾被GC回收掉。但是stringbuffer和stringbuilder則是在對同一個對象進行操作。

8.線程安全:線程安全就是多線程訪問時,採用了加鎖機制,只有一個線程訪問結束另一個線程纔可以進行訪問。非線程安全則沒有這樣的保護機制。

線程安全一般都是全局變量和靜態變量引起的。若每個線程對全局變量或靜態變量只有讀操作,一般來說是線程安全的,若多個線程執行寫操作,則要考慮同步問題。

線程安全:線程安全就是多線程訪問時,採用了加鎖機制,只有一個線程訪問結束另一個線程纔可以進行訪問。非線程安全則沒有這樣的保護機制。

線程安全一般都是全局變量和靜態變量引起的。若每個線程對全局變量或靜態變量只有讀操作,一般來說是線程安全的,若多個線程執行寫操作,則要考慮同步問題。

線程池:線程池在系統啓動時創建大量空閒線程,程序將一個Runnable對象傳給線程池,線程池就會啓動一條線程來執行該線程對象的run方法,當run方法執行結束後,該線程並不會死亡,而是再次返回線程池中成爲空閒線程,等待執行下一個Runnable對象的run方法。使用線程池可以有效地控制系統中併發線程的數量。

線程:進程中負責程序執行的單元,一個進程中至少有一個線程。

多線程:一個進程運行時產生了不止一個線程,在同一個應用程序中有多個功能流同時執行,多線程的切換是根據CPU切換完成。

1. 鎖表

鎖表的原理是數據庫使用獨佔式封鎖機制,當執行上面的語句時,對錶進行鎖住,直到發生commite 或者 回滾 或者退出數據庫用戶。

鎖表的原因

A程序執行了對 tableA 的 insert ,並還未 commite時,B程序也對tableA 進行insert 則此時會發生資源正忙的異常 就是鎖表。

鎖表常發生於併發而不是並行(並行時,一個線程操作數據庫時,另一個線程是不能操作數據庫的,cpu 和i/o 分配原則)

減少鎖表的概率:

減少insert 、update 、delete 語句執行 到 commite 之間的時間。例如批量執行改爲單個執行、優化sql自身的執行速度。如果異常對事物進行回滾。

2. 數據庫索引原理:平衡二叉樹和B+樹。

不是索引字段越多越好,建立一棵二叉樹需要空間,插入和變更數據需要調整二叉樹結構。B樹是多孩子節點的樹。

3. 如何檢查一個鏈表有沒有環。

定義一個指針一次走兩步,再定義一個指針一次走一步。如果兩個指針相遇,則代表有環。

1. 集合索引(聯合索引)

單一索引:在表的某一列上創建索引

聯合索引:在多個列上聯合創建索引

注意:查詢條件中出現聯合索引第一列,或者全部,則能使用聯合索引。

2. 類加載機制

類從被加載到虛擬機內存中開始,到卸載出內存爲止,它的整個生命週期包括:加載,驗證,準備,解析,初始化,使用和卸載七個階段。

類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,然後在堆區創建一個java.lang.Class對象,用來封裝類在方法區內的數據結構。類的加載的最終產品是位於堆區中的Class對象,Class對象封裝了類在方法區內的數據結構,並且向Java程序員提供了訪問方法區內的數據結構的接口

3. 3.GC回收機制

按代的垃圾回收機制:

新生代(Young generation): 絕大多數最新被創建的對象會被分配到這裏,由於大部分對象在創建後會很快變得不可到達,所以很多對象被創建在新生代,然後消失。對象從這個區域消失的過程我們稱之爲”minor GC“。

一個伊甸園空間 Eden + 兩個倖存者空間Survivor

1.絕大多數剛剛被創建的對象會存放在伊甸園空間。

2.在伊甸園空間執行了第一次GC之後,存活的對象被移動到其中一個倖存者空間。

3.此後,在伊甸園空間執行GC之後,存活的對象會被堆積在同一個倖存者空間。

4.當一個倖存者空間飽和,還在存活的對象會被移動到另一個倖存者空間。之後會清空已經飽和的那個倖存者空間。

5.在以上的步驟中重複幾次依然存活的對象,就會被移動到老年代

(其中一個倖存者空間一定是空的)

 

老年代(Old generation): 對象沒有變得不可達,並且從新生代中存活下來,會被拷貝到這裏。其所佔用的空間要比新生代多。也正由於其相對較大的空間,發生在老年代上的GC要比新生代少得多。對象從老年代中消失的過程,我們稱之爲”major GC“(或者”full GC

 

持久代( permanent generation )也被稱爲方法區method area)。他用來保存類常量以及字符串常量。因此,這個區域不是用來永久的存儲那些從老年代存活下來的對象。這個區域也可能發生GC。並且發生在這個區域上的GC事件也會被算爲major GC。

4. 3.動態規劃

動態規劃的核心思想是巧妙的將問題拆分成多個子問題,通過計算子問題而得到整體問題的解。而子問題又可以拆分成更多的子問題,從而用類似遞推迭代的方法解決要求的問題。

5. JAVA 中BIO,NIO,AIO的理解

同步和異步是針對應用程序和內核之間的交互完成的。

阻塞和非阻塞是針對於進程在訪問數據的時候,根據IO操作的就緒狀態來採取的不同方式。阻塞方式下讀取或者寫入函數將一直等待,而非阻塞方式下,讀取或者寫入函數會立即返回一個狀態值。

同步阻塞:你到飯館點餐,然後在那等着,還要一邊喊:好了沒啊!

同步非阻塞:在飯館點完餐,就去遛狗了。不過溜一會兒就回飯館喊一聲:好了沒啊!

異步阻塞:遛狗的時候,接到飯館電話,說飯做好了,讓您親自去拿。

異步非阻塞:飯館打電話說,我們知道您的位置,一會給送過去,安心遛狗就可以了。

一個IO操作分成兩個步驟:發起IO請求實際的IO操作

阻塞和非阻塞的區別在於第一步,發起IO請求是否會阻塞。同步和異步的區別在於第二步,如果實際的IO讀寫阻塞請求進程,那麼就是同步IO。

同步阻塞IO(JAVA BIO): 
    同步並阻塞,服務器實現模式爲一個連接一個線程,即客戶端有連接請求時服務器端就需要啓動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,當然可以通過線程池機制改善。

同步非阻塞IO(Java NIO) : 同步非阻塞,服務器實現模式爲一個請求一個線程,即客戶端發送的連接請求都會註冊到多路複用器上,多路複用器輪詢到連接有I/O請求時才啓動一個線程進行處理。用戶進程也需要時不時的詢問IO操作是否就緒,這就要求用戶進程不停的去詢問。 

異步阻塞IO(Java NIO):  
   此種方式下是指應用發起一個IO操作以後,不等待內核IO操作的完成,等內核完成IO操作以後會通知應用程序,這其實就是同步和異步最關鍵的區別,同步必須等待或者主動的去詢問IO是否完成,那麼爲什麼說是阻塞的呢?因爲此時是通過select系統調用來完成的,而select函數本身的實現方式是阻塞的,而採用select函數有個好處就是它可以同時監聽多個文件句柄

Java AIO)異步非阻塞IO:  
   在此種模式下,用戶進程只需要發起一個IO操作然後立即返回,等IO操作真正的完成以後,應用程序會得到IO操作完成的通知,此時用戶進程只需要對數據進行處理就好了,不需要進行實際的IO讀寫操作,因爲真正的IO讀取或者寫入操作已經由內核完成了。    

BIO方式適用於連接數目比較小且固定的架構。

NIO方式適用於連接數目多且連接比較短(輕操作)的架構,比如聊天服務器。

AIO方式使用於連接數目多且連接比較長(重操作)的架構,比如相冊服務器,充分調用OS參與併發操作。

綜上所述,同步和異步是相對於應用和內核的交互方式而言的,同步 需要主動去詢問,而異步的時候內核在IO事件發生的時候通知應用程序,而阻塞和非阻塞僅僅是系統在調用系統調用的時候函數的實現方式。

 

 

 

 

 

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