Java面試必備
1 、hashmap的底層,和hashtable,hashset有什麼區別?currenthashtable的底層? hashmap的實現方式陣列加連結串列,在jdk1.8以後使用陣列加二叉樹的結構。 hashcode採用31的原因是,因為可以利用移位操作代替乘法和減法操作,hashmap的初始容量為16載入因子為0.75。載入因子越大,就是啟用擴容的閾值越大,這表明hashmap所佔的記憶體越少,但是某一陣列上掛載的連結串列長度越長,所以搜尋速度越慢。hashset理論實現和hashmap是相同的,只是hashset的value值是確定的,而且hashmap屬於map而hashset屬於collection。 hashmap是執行緒不安全的,hashtable是執行緒安全的,並且hashtable的實現方式是拉鍊法。另外hashmap是快速失敗的,而hashtable不是,hashtable的鍵可以為null,但是hashtable不允許。 currenthashmap和hashmap一樣都是執行緒安全的,但是currenthashmap是對每一個段資料都配有一個鎖,而hashtable如果發生寫操作時,將會對整個表加鎖,相對於currenthashmap而言,可靠性要高,但是速度慢。 concurrenthashmap是二級hashmap,第一層維護segment,第二層是每個segment維護的元素組成的hashmap結構。 一個currenthashmap裡包含一個Segment陣列,Segment的結構和HashMap類似,是一種陣列和連結串列結構, 一個Segment裡包含一個HashEntry陣列,每個HashEntry是一個連結串列結構的元素, 每個Segment守護者一個HashEntry數組裡的元素,當對HashEntry陣列的資料進行修改時,必須首先獲得它對應的Segment鎖。 ConcurrentHashMap的get操作
public V get(Object key) {
int hash = hash(key.hashCode());
return segmentFor(hash).get(key, hash);
}
get方法定義成volatile的變數,能夠線上程之間保持可見性,能夠被多執行緒同時讀,並且保證不會讀到過期的值,但是隻能被單執行緒寫(有一種情況可以被多執行緒寫,就是寫入的值不依賴於原值),在get操作裡只需要讀不需要寫共享變數count和value,所以可以不用加鎖。之所以不會讀到過期的值,是根據java記憶體模型的happen before原則,對volatile欄位的寫入操作先於讀操作,即使兩個執行緒同時修改和獲取volatile變數,get操作也能拿到最新的值,這是用volatile替換鎖的經典應用場景。
transient volatile int count;
volatile V value;
在定位元素的程式碼裡我們可以發現定位HashEntry和定位Segment的雜湊演算法雖然一樣,都與陣列的長度減去一相與,但是相與的值不一樣,定位Segment使用的是元素的hashcode通過再雜湊後得到的值的高位,而定位HashEntry直接使用的是再雜湊後的值。其目的是避免兩次雜湊後的值一樣,導致元素雖然在Segment裡雜湊開了,但是卻沒有在HashEntry裡雜湊開。
hash >>> segmentShift) & segmentMask//定位Segment所使用的hash演算法 int index = hash & (tab.length - 1);// 定位HashEntry所使用的hash演算法
ConcurrentHashMap的Put操作 由於put方法裡需要對共享變數進行寫入操作,所以為了執行緒安全,在操作共享變數時必須得加鎖。Put方法首先定位到Segment,然後在Segment裡進行插入操作。插入操作需要經歷兩個步驟,第一步判斷是否需要對Segment裡的HashEntry陣列進行擴容,第二步定位新增元素的位置然後放在HashEntry數組裡。 是否需要擴容。在插入元素前會先判斷Segment裡的HashEntry陣列是否超過容量(threshold),如果超過閥值,陣列進行擴容。值得一提的是,Segment的擴容判斷比HashMap更恰當,因為HashMap是在插入元素後判斷元素是否已經到達容量的,如果到達了就進行擴容,但是很有可能擴容之後沒有新元素插入,這時HashMap就進行了一次無效的擴容。 如何擴容。擴容的時候首先會建立一個兩倍於原容量的陣列,然後將原數組裡的元素進行再hash後插入到新的數組裡。為了高效ConcurrentHashMap不會對整個容器進行擴容,而只對某個segment進行擴容。
ConcurrentHashMap的size操作 ConcurrentHashMap的做法是先嚐試2次通過不鎖住Segment的方式來統計各個Segment大小,如果統計的過程中,容器的count發生了變化,則再採用加鎖的方式來統計所有Segment的大小。那麼ConcurrentHashMap是如何判斷在統計的時候容器是否發生了變化呢?使用modCount變數,在put , remove和clean方法裡操作元素前都會將變數modCount進行加1,那麼在統計size前後比較modCount是否發生變化,從而得知容器的大小是否發生變化。
2 、spring 的aop你怎麼看?Spring的aop怎麼實現?Spring的aop有哪些實現方式 aop是spring兩大特點中的一個,aop翻譯過來是面向切面,而與面向物件不同的是面向切面是一個寄生程式設計方式。主要包括,切入點,連線點,切面,織入,通知。 aop動態代理的方法可以使用jdk動態代理或者CGLIB動態代理,前者基於介面,後者基於子類。 xml開發例子:
<bean id="helloworld" class="myaop.HelloWorldImpl1">
</bean>
<bean id="printtime" class="myaop.printtime"></bean>
<aop:config>
<aop:aspect id="dotime" ref="printtime">切面類
<aop:pointcut id="adddoMethod"
expression="execution(* myaop.HelloWorldImpl1.do*(..))" />執行時
<aop:before method="syso" pointcut-ref="adddoMethod" />
前一個是切面的方法,後一個是被切的方法,意思是在adddpmethod之前執行syso方法,是poincut。
<aop:after method="syso" pointcut-ref="adddoMethod" />
</aop:aspect>
<aop:aspect id="printtime" ref="printtime">
<aop:pointcut id="addprintMethod"
expression="execution(* myaop.HelloWorldImpl1.print*(..))" />
<aop:before method="logging" pointcut-ref="addprintMethod" />
</aop:aspect>
</aop:config>
</beans>
3 、索引有什麼用?索引失效問題?索引分類?用途? https://blog.csdn.net/timer_gao/article/details/78013826 傳統無索引情況下,如果需要查詢某一欄位的資料時需要 https://blog.csdn.net/waeceo/article/details/78702584 4 、資料庫引擎,儲存結構 mysql常用資料引擎有 InnoDB 預設引擎,支援事務,支援外來鍵,支援行級鎖。mysql在執行innodb時會再記憶體中建立緩衝池,用於緩衝資料和索引。但該引擎不支援FULLTEXT型別的索引,而且不儲存行數,因此當select count(*) form table需要掃描全表。另外索引採用是聚集索引,因此必須確定primary key,如果使用者不指定,將自動選定一個欄位作為主鍵,如果不存在這種列,將使用隱含欄位。 Isam Myisam isam的擴充套件版本,沒有事務,索引採用非聚集索引,可以沒有主鍵。 memory 與redis類似,是記憶體資料庫,使用hash索引
myisam和innodb選擇? innodb 1 可靠性要求高,需要事務 2 插入和查詢都很頻繁 myisam 1 沒有事務 2 做count運算 3 插入不頻繁,查詢頻繁
5 、spring 的理解?bean的實現方式?bean的生命週期,作用域 1 core 是最基礎的部分,主要提供ioc功能,基礎概念是bean工廠 2 context 構築於core包之上,國際化,事務傳播,資源載入,以及透明建立上下文 3 aop 面向切面程式設計的包 4 dao 提供了jdbc的抽象層,並且提供了事務管理 5 orm 提供了hibernate,mybaits的介面 6 mvc提供了mvc 的實現 7 web 提供了對structs2 或者webword 的介面 bean的實現詳見https://blog.csdn.net/wuzhengfei1112/article/details/74056324 bean的建立分為兩部分, 第一部是解析xml 第二部是生成beanfactory bean的生命週期和作用域 生命週期:Spring 只幫我們管理單例模式 Bean 的完整生命週期,對於 prototype 的 bean ,Spring 在建立好交給使用者之後則不會再管理後續的生命週期 下圖是singleton的生命週期: 作用域:singleton,prototype,session,globalsession,request
6、快排和歸併和堆排的演算法。 快排
public class QuickSort {
public static void quickSortHelp(int[] arr) {
quickSort(arr,0, arr.length-1);
}
public static void quickSort(int[] arr,int low, int high) {
if(low<high) {
int partition = partition(arr,low,high);
quickSort(arr,low, partition-1);
quickSort(arr,partition+1, high);
}
}
public static int partition(int[] arr,int low,int high) {
while(low<high) {
while(arr[high]>=arr[low]&&low<high){
high--;
}
Swap(arr,high,low);
while(arr[low]<=arr[high]&&low<high) {
low++;
}
Swap(arr,high,low);
}
return low;
}
public static void Swap(int[] arr,int high,int low) {
int temp = arr[low];
arr[low] =arr[high];
arr[high] = temp;
}
public static void main(String[] args) {
int[] array = { 2, 8, 5, 6, 10, 5, 4, 6, 11, 15, 3 };
quickSortHelp(array);
for (int s : array) {
System.out.println(s);
}
}
}
7、代理模式
package daili;
public interface Account {
//查詢功能
public void queryAccount();
//修改功能
public void updateAccount();
}
package daili;
public class AccountImpl implements Account {
@Override
public void queryAccount() {
System.out.println("委託類的查詢方法...");
}
@Override
public void updateAccount() {
System.out.println("委託類的修改方法.....");
}
}
package daili;
public class AccountProxy implements Account {
private AccountImpl accountImpl;
/**
*
* @Title: AccountProxy
* @Description: 重寫預設的建構函式。真正執行的業務物件是accountImpl
* @param: @param accountImpl
* @throws
*/
public AccountProxy(AccountImpl accountImpl){
this.accountImpl=accountImpl;
}
@Override
public void queryAccount() {
System.out.println("查詢業務處理之前...");
accountImpl.queryAccount();
System.out.println("查詢業務處理之後....");
}
@Override
public void updateAccount() {
System.out.println("修改業務處理之前...");
accountImpl.queryAccount();
System.out.println("修改業務處理之後....");
}
}
package daili;
public class Test {
public static void main(String[] args) {
AccountImpl accountImpl=new AccountImpl();
AccountProxy accountProxy=new AccountProxy(accountImpl);
accountProxy.queryAccount();
accountProxy.updateAccount();
}
}
動態代理https://www.cnblogs.com/baizhanshi/p/6611164.html aop主要使用動態代理和反射
8、執行緒鎖有哪些?資料庫鎖有哪些 synchronize,volatile,lock 行鎖,表鎖,悲觀鎖,樂觀鎖 表鎖:行共享,行排他,共享鎖,共享行排他,排他 https://www.cnblogs.com/sessionbest/articles/8689071.html 9、執行緒池型別?執行緒池設定引數,執行緒返回值 4種常用的執行緒池,其實是Threadpoolexecuter的通過引數設定後得到的定製的執行緒池 newScheduleThreadPool 可以根據計劃進行執行緒執行。 ** newSingleThreadExecutor** 執行緒池中只有一條執行緒,保證滿足FIFO的形式 newFixedThreadPool 固定數量執行緒數的執行緒池,核心執行緒數和最大執行緒數相同,外部輸入。如果大於這個就加入阻塞佇列,阻塞佇列滿了就返回失敗。 newCachedThreadPool 可以定製計劃的執行緒池,使用syschronousqueue,有核心執行緒數量,最大執行緒為無窮大,即可以無窮建立,但是涉及記憶體問題 上面的執行緒池都是改變threadpoolexecutor引數實現,就是定製的threadpool,當然可以自己實現 常用threadpoolexecutor int corePoolSize,核心執行緒數 int maximumPoolSize,最大維護執行緒池 long keepAliveTime,超過核心池數量的執行緒的時間 TimeUnit unit,時間單位 BlockingQueue workQueue,
五種阻塞佇列 1SynchronousQueue:無快取,使用cas輪詢實現,消費者和生產者的互動 2LinkedBlockingQueue:有快取的連結串列阻塞佇列,在LinkedBlockingQueue中維護了一條連結串列,可以設定連結串列的最大長度。採用分離鎖,可以併發執行,速度快 3ArrayBlockingQueue:有快取的陣列阻塞佇列,在ArrayBlockingQueue中維護了一條定長的陣列。生產者和消費者共用一個鎖物件,兩者無法真正意義上的並行,之所以不採用分離鎖是因為這種阻塞佇列已經足夠輕量,所以加入分離鎖後悔變複雜 4DelayQueue:只有達到延時時間才能取到元素,大小沒有限制 5 PriorityBlockingQueue基於優先順序的阻塞佇列,注意的是隻會阻塞消費者不阻塞生產者,因此如果生產者速度大於消費者,會耗盡堆記憶體空間。 10 、分頁怎麼實現的 分頁有兩種方式,一種物理分頁,即使用limit 。另一種是使用遊標,也稱為邏輯分頁
11、三次握手四次揮手都做了什麼 三次握手: 1 TCP伺服器首先建立傳輸控制塊TCB,時刻準備接受客戶程序的連線請求,進入LISTEN(監聽狀態) 2 TCP客戶程序也先建立傳輸控制塊TCB,然後向伺服器傳送連線請求,此時報文同部位的SYN=1,同時選擇一個初始序列號seq=x;此時tcp客戶端進入到SYN-SENT階段。 3 TCP服務端收到連線請求,如果同意連線則,發出確認報文,SYN=1,ACK=1,seq=y,ack=x+1,此時伺服器進入SYN-RCVD狀態 4 TCP客戶端收到確認後向伺服器發出確認,報文ACK=1,seq=x+1,ack=y+1; 5 進入establish狀態 進行三次握手而不是兩次是因為如果發生延時在客戶端向伺服器端傳送請求時,那麼伺服器將直接和客戶機建立連線,而此時客戶機可能已經不想要了,造成資源浪費,而進行三次握手相當於客戶機向伺服器再次確認需要建立連線,保證了實時性和有效性
四次揮手: 1原本是establish狀態,客戶端和服務端 2客戶端主動關閉,發出關閉請求FIN=1,seq=u,進入FIN-WAIT-1狀態 3伺服器收到關閉請求,如果同意,發出ACK=1,seq=v,ack=u+1,進入close-wait狀態 4客戶機收到後進入FIN-WAIT-2狀態 5伺服器再次發出FIN=1,ACK=1,seq=w,ack=u+1,進入LAST-ACK 6客戶機收到後發出ACK=1,seq=u+1.ack=w+1,進入TIME-WAIT狀態 7伺服器收到後關閉 8客戶端等待2MSL關閉
等待2MSL 等待2MSL是因為首先保證客戶端向服務傳送的確認報文,伺服器可以收到,如果沒收到,伺服器會再發一個確認報文,在這個時間內客戶機人處於time-wait狀態,可以重傳確認報文 第二點,是保證在這個時間內,這個舊的報文段可以從網路中消失,保證新的報文的有效性。 建立連線的時候, 伺服器在LISTEN狀態下,收到建立連線請求的SYN報文後,把ACK和SYN放在一個報文裡傳送給客戶端。 握手三次揮手四次問題 關閉連線時,伺服器收到對方的FIN報文時,僅僅表示對方不再發送資料了但是還能接收資料,而自己也未必全部資料都發送給對方了,所以己方可以立即關閉,也可以傳送一些資料給對方後,再發送FIN報文給對方來表示同意現在關閉連線,因此,己方ACK和FIN一般都會分開發送,從而導致多了一次 參考:https://blog.csdn.net/qzcsu/article/details/72861891
12、java虛擬機器記憶體管理,類的載入和雙親委派 堆,棧,靜態成員 堆,本地方法棧,程式計數器,jvm棧,方法區。其中本地方法棧,jvm棧和程式計數器是不共享的,而堆和方法區是共享的。 本地方法棧主要是其他編碼語言開發的一些方法和介面 jvm棧是區域性的變數 程式計數器是位元組碼記錄程式以及方法的入口 方法區是,類載入時儲存靜態成員的區域,包括編譯後的程式碼,常量,靜態常量,類資訊。 堆是物件儲存的區域,根據新生代和老生代分為三個區域,兩個servior,一個eden,一個老生代區 類載入過程 載入連線和初始化。其中連線分為驗證,準備,和解析 驗證:確保載入的類資訊符合JVM規範,沒有安全方面的問題 準備:正式為類變數(static變數)分配記憶體並設定類變數初始值的階段,這些記憶體都將在方法去中進行分配 解析:虛擬機器常量池的符號引用替換為位元組引用過程 載入器有,啟動類載入器,擴充套件類載入器,應用程式類載入器,使用者自定義類載入器 雙親委派模型是指:當一個類載入器收到載入任務時,並不會立刻執行載入,而是把類載入向父載入器丟擲,如果父類處理不了就繼續向上丟擲,直到頂層類載入器也處理不了,就嘗試自己執行載入任務,這些做的好處是永遠只加載唯一的類。
13、垃圾回收,回收什麼?什麼時候回收?怎樣發現?怎樣清理?新生代老生代永久代? 垃圾回收是回收物件 和方法區中的是不使用的物件,回收時間新建一個物件後,如果eden已滿,就會在用minor gc回收不常用物件。如果年老代的滿的時候,利用fullgc,進行垃圾回收。 發現:包括兩種方法: 一種是計數法,每當一個地方引用物件時,計數器值加一,引用失效計數器減1,任何時刻計數器為0的物件表示不再被使用,但是由於這種方法解決不了相互引用問題,所以jvm不使用這種方法。 另一種是可達性分析法,即以一系列的gc root的物件為初始物件,從這些節點向下搜尋,搜尋走過的路徑為引用鏈,當一個物件到gcroot沒有任何引用,即不可達時,則證明此物件不可達。可以選用方法區的常量應用物件,虛擬機器棧,本地方法棧為gcroots。 清理: 標記-清除:這種方法通過上述的發現方法後,利用清除方法對物件進行清除,但是這種方法會留下大量的碎片,這可能導致需要連續記憶體時需要重複執行低效的演算法。 複製演算法:將記憶體分成兩塊,每次用一塊記憶體,如果記憶體用完後,將存活物件複製到另一塊中,而使用過的記憶體空間直接清理。但是這種方法非常耗費記憶體,因為要分成兩塊。一般利用這種演算法清理新生代。 壓縮演算法:將活動的物件都向另一端移動,清理邊界以外的記憶體。 結合上面三種基本演算法:目前商用虛擬機器採用分代收集演算法。對於大批物件死去,少量存活的新生代使用複製演算法,而對於存活率高的老年代使用壓縮或者標記清楚 常見收集器 序列收集器,單條執行緒收集,暫停其他執行緒工作 並行收集器,多執行緒,伺服器收集。 CMS併發收集器多執行緒標記清除,不暫停 G1 收集器多執行緒,主執行緒暫停並行,否則併發,取消物理層面的新生代和年老代的劃分,並且有巨型物件直接放置在年老代 參考https://www.cnblogs.com/ASPNET2008/p/6496481.html
新生代利用複製演算法,而老生代使用標記清除或者壓縮演算法,為fullgc。新生代有三個區,兩個surivior,一個eden,比例為1:1:8。新建的物件一般位於eden中,如果在第一次垃圾回收後,仍然處於活躍狀態,則將其放入surivior中,如果倖存15次,則將這個物件移入到老生代。surivior一個是from,一個是to,每一次回收都會清空eden,並將活動的surivior中的物件從一個複製到另一個。
14、表的insert,delete,update,select,inner join on,left join on,right join on,以及sort 等基本操作,以及一對多,一對一,多對多的處理。
15、 事務的隔離級別和傳輸特性 三個問題,髒讀,不可重複讀,幻讀 四種隔離級別 未提交讀,不解決問題 提交讀,解決髒讀 可重複讀,解決髒讀和不可重複讀 序列化,解決髒讀,不可重複讀,幻讀 八種傳輸特性 如果有事務則使用事務如果沒有則不使用 support 如果有事務使用事務如果沒有則建立事務 requested 如果有事務使用事務,如果沒有丟擲異常 如果有事務掛起當前事務,另外建立事務,沒有事務建立事務 如果有事務則掛起當前事務,不使用事務,沒有事務也不建立 如果有事務則掛起當前事務,並丟擲異常 事務巢狀
16、什麼是redis?解決什麼問題?redis的淘汰策略和調優,持久化?穿透和雪崩分別指什麼?怎麼處理? Redis是一款k-v記憶體資料庫,可以解決高併發和高效能問題 redis的淘汰策略主要有 從過期資料中剔除使用最少的資料 volatile-lru 從過期資料中剔除隨機資料 volatile-lru 從所有資料中剔除使用頻率最低的資料allkeys-lru 從所有資料中剔除隨機資料 allkeys-random 從過期中選擇即將過期資料 volatile-ttl 禁止剔除資料 noeviction 快照和aof· 快照是將資料直接儲存,aof是利用日誌儲存 穿透是指黑客一直訪問記憶體資料庫中不存在的資料,導致這些資料都落在了硬碟資料庫中,導致資料庫壓力增大,從而宕機 雪崩是指資料量過大,或者記憶體資料庫有部分宕機,導致記憶體資料庫處理不了這麼大資料量,使得這些請求都在硬碟資料庫中,使得伺服器宕機 雪崩的解決方法 前:建立完善的redis叢集,以及良好的記憶體更新方案,和適合的備份方案 中:使用訪問控制系統,限流 後:快速恢復記憶體資料庫
17、介面和抽象類的區別,注意JDK8的介面可以有實現。 1介面中所有的方法都是抽象的,但是抽象類中有普通方法 2可以實現多個介面但是隻能繼承一個類 3介面只有方法名,抽象類可以有方法體,但是在jdk1.8介面也可以有方法體,但必須是default修飾的。 4介面沒有構造器,而抽象函式有構造器 5介面只能用public修飾,但是抽象類可以用default,public,prodected修飾 6介面中沒有main方法,但是抽象類中可以有 7介面中新增方法,必須修改實現它的所有類,但是抽象類可以預設方法。
18、Java序列化的方式,如何在序列化過程中使得某些元素保密 序列化:物件轉為二進位制碼傳輸 反序列化:將二進位制編碼轉換回物件
19、什麼是反射?為什麼使用反射?你平時在哪些框架遇見過反射? 在執行時動態載入類。 Java反射機制主要提供了以下功能:在執行時構造一個類的物件;判斷一個類所具有的成員變數和方法;呼叫一個物件的方法;生成動態代理。反射最大的應用就是框架 Java反射的主要功能: 1確定一個物件的類 2取出類的modifiers,資料成員,方法,構造器,和超類. 3找出某個接口裡定義的常量和方法說明. 4建立一個類例項,這個例項在執行時刻才有名字(執行時間才生成的物件). 5取得和設定物件資料成員的值,如果資料成員名是執行時刻確定的也能做到. 6在執行時刻呼叫動態物件的方法. 7建立陣列,陣列大小和型別在執行時刻才確定,也能更改陣列成員的值. 反射的應用很多,很多框架都有用到 spring 的 ioc/di 也是反射…. javaBean和jsp之間呼叫也是反射…. struts的 FormBean 和頁面之間…也是通過反射呼叫…. JDBC 的 classForName()也是反射…… hibernate的 find(Class clazz) 也是反射…. 反射還有一個不得不說的問題,就是效能問題,大量使用反射系統性能大打折扣。 **20、jdbc的使用,jdbc連線池,有什麼封裝好的jdbc工具
<!-- c3p0連線池配置 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 使用者名稱-->
<property name="user" value="${username}"/>
<!-- 使用者密碼-->
<property name="password" value="${password}"/>
<property name="driverClass" value="${driver_class}"/>
<property name="jdbcUrl" value="${url}"/>
<!--連線池中保留的最大連線數。預設值: 15 -->
<property name="maxPoolSize" value="20"/>
<!-- 連線池中保留的最小連線數,預設為:3-->
<property name="minPoolSize" value="2"/>
<!-- 初始化連線池中的連線數,取值應在minPoolSize與maxPoolSize之間,預設為3-->
<property name="initialPoolSize" value="2"/>
<!--最大空閒時間,60秒內未使用則連線被丟棄。若為0則永不丟棄。預設值: 0 -->
<property name="maxIdleTime">60</property>
<!-- 當連線池連線耗盡時,客戶端呼叫getConnection()後等待獲取新連線的時間,超時後將丟擲SQLException,如設為0則無限期等待。單位毫秒。預設: 0 -->
<property name="checkoutTimeout" value="3000"/>
<!--當連線池中的連線耗盡的時候c3p0一次同時獲取的連線數。預設值: 3 -->
<property name="acquireIncrement" value="2"/>
<!--定義在從資料庫獲取新連線失敗後重復嘗試的次數。預設值: 30 ;小於等於0表示無限次-->
<property name="acquireRetryAttempts" value="0"/>
<!--重新嘗試的時間間隔,預設為:1000毫秒-->
<property name="acquireRetryDelay" value="1000" />
<!--關閉連線時,是否提交未提交的事務,預設為false,即關閉連線,回滾未提交的事務 -->
<property name="autoCommitOnClose">false</property>
<!--c3p0將建一張名為Test的空表,並使用其自帶的查詢語句進行測試。如果定義了這個引數那麼屬性preferredTestQuery將被忽略。你不能在這張Test表上進行任何操作,它將只供c3p0測試使用。預設值: null -->
<property name="automaticTestTable">Test</property>
<!--如果為false,則獲取連線失敗將會引起所有等待連線池來獲取連線的執行緒丟擲異常,但是資料來源仍有效保留,並在下次呼叫getConnection()的時候繼續嘗試獲取連線。如果設為true,那麼在嘗試獲取連線失敗後該資料來源將申明已斷開並永久關閉。預設: false-->
<property name="breakAfterAcquireFailure">false</property>
<!--每60秒檢查所有連線池中的空閒連線。預設值: 0,不檢查 -->
<property name="idleConnectionTestPeriod">60</property>
<!--c3p0全域性的PreparedStatements快取的大小。如果maxStatements與maxStatementsPerConnection均為0,則快取不生效,只要有一個不為0,則語句的快取就能生效。如果預設值: 0-->
<property name="maxStatements">100</property>
<!--maxStatementsPerConnection定義了連線池內單個連線所擁有的最大快取statements數。預設值: 0 -->
<property name="maxStatementsPerConnection"></property>
</bean>
21、日誌的實現方式,安全的實現方式? Java Logging API(Oracle)—— Java預設的日誌框架 Log4j(Apache)——開源日誌框架 Logback(Logback Project)——開源專案,被設計成Log4j版本1的後續版本 tinylog(tinylog)——輕量級開源logger 22、一共設計了多少表,每個表的欄位是什麼?mysql的優化手段? 管理員表 id,使用者名稱,密碼 使用者表 id,使用者名稱,密碼,帖子數 部落格表 id, 部落格名,部落格詳情,使用者外來鍵 評論表 id,評論內容,評論時間,外來鍵評論使用者,外來鍵部落格使用者名稱 登入人員表 id ,登入時間,登入次數。外來鍵使用者
23、hibernate的幾種狀態
24、多執行緒Java實現多執行緒有哪幾種方式。Callable和Future的瞭解 繼承Thread,實現runnable介面 之所以又有Callable和Future是因為前兩種方式並沒有返回值,為了獲得返回值,可以採用callable和future,或者callable和futuretask。其他獲得執行緒返回值的方法是共享變數,或者利用wait和notify和notifyall實現執行緒間的通訊。
package mythread2;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
class SumTask implements Callable<Long> {
@Override
public Long call() throws Exception {
long sum = 0;
for (int i = 0; i < 9000; i++) {
sum += i;
}
return sum;
}
}
public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Long> futureTask=new FutureTask<>(new SumTask());
Executor executor= Executors.newSingleThreadExecutor();
executor.execute(futureTask);
System.err.println(futureTask.get());
try {
System.err.println();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
25、Lock介面有哪些實現類,使用場景是什麼。可重入鎖的用處及實現原理,寫時複製的過程,讀寫鎖,分段鎖(ConcurrentHashMap中的segment)。悲觀鎖,樂觀鎖,優缺點,CAS有什麼缺陷,該如何解決。ABC三個執行緒如何保證順序執行。 lock 介面下有重入鎖和讀寫鎖兩個,重入鎖的使用場景和synchronize類似,但是具有更強大的功能,就是互斥鎖。 讀寫鎖,是將鎖分為讀鎖和寫鎖,一般情況下,寫鎖只能由一個執行緒持有,讀鎖由多個執行緒持有,並且讀讀共享,讀寫互斥,寫寫互斥,即寫的時候,其他執行緒不允許寫或讀,讀的時候,其他執行緒不允許寫。 悲觀鎖,就是不管是否發生多執行緒衝突,只要存在這種可能,就每次訪問都加鎖,加鎖就會導致鎖之間的爭奪,有爭奪就會有輸贏,輸者等待。 syncrhoized是一種獨佔鎖,即:佔用該鎖的執行緒才可以執行,申請該鎖的執行緒就只能掛起等待,直到佔用鎖的執行緒釋放鎖才喚醒,拿到鎖並執行。由於在程序掛起和恢復執行過程中存在著很大的開銷,並且當一個執行緒正在等待鎖時,它不能做任何事。所以syncrhoized是一種悲觀鎖,凡是用syncrhoized加了鎖的多執行緒之間都會因鎖的爭奪結果導致掛起、喚醒等開銷。 樂觀鎖獲得鎖後一直持有鎖以防本執行緒再次申請該鎖造成無謂的解鎖再加鎖開銷,或者假設沒有衝突而去完成同步程式碼塊如果衝突再迴圈重試,或者採取申請鎖失敗後不立刻掛起而是稍微等待再次嘗試獲取 等待策略,以減少執行緒因為掛起、阻塞、喚醒(發生CPU的排程切換) 而造成的開銷。偏向鎖、輕量級鎖(CAS輪詢)、自旋鎖 就是基於上述思路的樂觀鎖。 在多執行緒的加鎖機制中,JVM會首先嚐試樂觀鎖,失敗後才呼叫悲觀鎖。 CAS(Compare-and-Swap)實現樂觀鎖的手段,通過輪詢實現樂觀鎖 目前大部分鎖都是利用cas,如atomic類,以及lock底層,synchronize未轉換為重量鎖之前一直使用cas的手段。 cas的缺點:只能保證變數的原子性不能保證程式碼塊的原子性 對cpu資源有壓力 ABA問題,利用版本號解決 ABC三個執行緒如何保證順序執行:用join解決,讓並行變為序列。
package mythread2;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class mylock {
static Lock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
mythread2 mythread2 = new mythread2();
mythread1 mythread1 = new mythread1(mythread2);
mythread1.start();
mythread2.start();
}
}
class mythread1 extends Thread {
mythread2 mythread2 = new mythread2();
public mythread1(mythread2 mythread2) {
// TODO Auto-generated constructor stub
this.mythread2=mythread2;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
try {
mythread2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mylock.lock.lock();
System.out.print("國");
System.out.print("親");
System.out.print("節");
System.out.print("快");
System.out.print("樂");
System.out.println();
mylock.lock.unlock();
}
}
}
class mythread2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
mylock.lock.lock();
System.out.print("好");
System.out.print("運");
System.out.print("連");
System.out.print("連");
System.out.print("連");
System.out.println();
mylock.lock.unlock();
}
}
}
重入鎖reentrantlock和synchronize的區別
-
ReenTrantLock可以指定是公平鎖還是非公平鎖。而synchronized只能是非公平鎖。所謂的公平鎖就是先等待的執行緒先獲得鎖。
-
ReenTrantLock提供了一個Condition(條件)類,用來實現分組喚醒需要喚醒的執行緒們,而不是像synchronized要麼隨機喚醒一個執行緒要麼喚醒全部執行緒。
-
ReenTrantLock提供了一種能夠中斷等待鎖的執行緒的機制,通過lock.lockInterruptibly()來實現這個機制。
重入鎖使用
package mythread2;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class mylock {
static Lock lock = new ReentrantLock();
public static void main(String[] args) {
new mythread1().start();
new mythread2().start();
}
}
class mythread1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
mylock.lock.lock();
System.out.print("國");
System.out.print("親");
System.out.print("節");
System.out.print("快");
System.out.print("樂");
System.out.println();
mylock.lock.unlock();
}
}
}
class mythread2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
mylock.lock.lock();
System.out.print("好");
System.out.print("運");
System.out.print("連");
System.out.print("連");
System.out.print("連");
System.out.println();
mylock.lock.unlock();
}
}
}
26、執行緒的狀態都有哪些。sleep和wait的區別。notify和notifyall的區別。ThreadLocal的瞭解,實現原理。 新建狀態,就緒狀態,執行狀態,阻塞狀態,死亡狀態,五種 阻塞狀態又分為三種:等待阻塞(wait),同步阻塞(synchronize),其他阻塞(sleep,join以及io) 27、Jvm的引數設定 CATALINA_OPTS=" -server :一般應用於伺服器端,啟動慢,記憶體管理效率高,對應的是-client 應用於客戶端,啟動快,但是記憶體管理效率低 -Xms6000M 初始java堆的大小,一般將其設定為和xmx相同大小,避免jvm反覆申請記憶體而導致效能起伏 -Xmx6000M 最大堆大小,如果應用程式記憶體大於該值就會使得jvm奔潰,一般設定為記憶體的80% -Xss512k 棧大小,在jdk5以前設定為256,5以後設定為1m。減小此值將會容納更多的執行緒,但是也會導致outofmemory,一般不設定為1m,256夠用 -XX:NewSize=2250M 新生代堆大小,新生代堆包括eden,和survior,大小比一般為8:1:1 -XX:MaxNewSize=2250M 最大新生代堆大小 -XX:PermSize=128M 永久代堆大小 -XX:MaxPermSize=256M 永久代最大堆大小 -XX:+AggressiveOpts 加入最新的優化技術 -XX:+UseBiasedLocking 使用優化鎖 -XX:+DisableExplicitGC 不允許使用system.gc防止效能不懂 -XX:+UseParNewGC 對新生代使用並行回收 -XX:+UseConcMarkSweepGC 年老代並行回收 -XX:MaxTenuringThreshold=31 升級為年老代的計數值 -XX:+CMSParallelRemarkEnabled
-XX:+UseCMSCompactAtFullCollection
-XX:LargePageSizeInBytes=128m 分頁大小 -XX:+UseFastAccessorMethods get,set方法轉化為本地編碼 -XX:+UseCMSInitiatingOccupancyOnly
-Duser.timezone=Asia/Shanghai 時區設定 -Djava.awt.headless=true" -XX:NewRatio 4 表示年輕代比年老代為1:4
28、紅黑樹和b樹,二叉查詢樹,堆,最大堆和最小堆 紅黑樹是一種自平衡二叉樹 b樹balance多叉樹,b+樹比b樹多了同級引用 二叉查詢樹的性質是必須是沒有重複的數字,所以適合map,當然是變形以後,其實二叉查詢樹的建立類似於插入排序。 **堆是滿二叉樹 29、記憶體屏障是什麼 記憶體屏障(Memory Barrier,或有時叫做記憶體柵欄,Memory Fence)是一種CPU指令,用於控制特定條件下的重排序和記憶體可見性問題。Java編譯器也會根據記憶體屏障的規則禁止重排序。 記憶體屏障可以被分為以下幾種型別 LoadLoad屏障:對於這樣的語句Load1; LoadLoad; Load2,在Load2及後續讀取操作要讀取的資料被訪問前,保證Load1要讀取的資料被讀取完畢。 StoreStore屏障:對於這樣的語句Store1; StoreStore; Store2,在Store2及後續寫入操作執行前,保證Store1的寫入操作對其它處理器可見。 LoadStore屏障:對於這樣的語句Load1; LoadStore; Store2,在Store2及後續寫入操作被刷出前,保證Load1要讀取的資料被讀取完畢。 StoreLoad屏障:對於這樣的語句Store1; StoreLoad; Load2,在Load2及後續所有讀取操作執行前,保證Store1的寫入對所有處理器可見。它的開銷是四種屏障中最大的。 在大多數處理器的實現中,這個屏障是個萬能屏障,兼具其它三種記憶體屏障的功能。 有的處理器的重排序規則較嚴,無需記憶體屏障也能很好的工作,Java編譯器會在這種情況下不放置記憶體屏障。 為了實現上一章中討論的JSR-133的規定,Java編譯器會這樣使用記憶體屏障。 為了保證final欄位的特殊語義,也會在下面的語句加入記憶體屏障。 x.finalField = v; StoreStore; sharedRef = x; https://www.cnblogs.com/chenyangyao/p/5269622.html 30、Object類下的方法 tostring equals hashcode wait notify notifyall getclass finalize clone 31、bio、nio和aio的區別 bio 同步阻塞 nio 非同步阻塞 aio 非同步非阻塞 詳情:https://blog.csdn.net/huangwenyi1010/article/details/75577091 32、Synchronize原理?lock原理?volitile原理?三者區別?i++執行緒安全?在1.6後synchronize的效能提升? synchronize 是jvm控制的內建鎖 lock是程式設計實現的顯式鎖 volitile是關鍵字 synchronize 和Reentrantlock都是同步的,而且都是阻塞式同步,並且都是可重入鎖。synchronize是jvm實現的,而lock是api層面實現的,而且需要lock和unlock聯合try…finally使用。同時synchronize是非公平鎖,lock預設是非公平鎖,但是可以通過設定,將lock轉為公平鎖。synchronize是獨享鎖,reentrantlock也是獨享鎖,但是readwritelock的讀共享鎖寫是獨享鎖,通過aqs實現。同時lock等待可以中斷,但是synchronize不行。
在jdk1.6,加入了偏向鎖,輕量級鎖,自旋鎖和重量級鎖,隨著併發程度的增大,逐漸升級但是不能降級。 33、生產者和消費者模式
synchronized、wait和notify 方法實現
package producerConsumer;
//wait 和 notify
public class ProducerConsumerWithWaitNofity {
public static void main(String[] args) {
Resource resource = new Resource();
//生產者執行緒
ProducerThread p1 = new ProducerThread(resource);
ProducerThread p2 = new ProducerThread(resource);
ProducerThread p3 = new ProducerThread(resource);
//消費者執行緒
ConsumerThread c1 = new ConsumerThread(resource);
//ConsumerThread c2 = new ConsumerThread(resource);
//ConsumerThread c3 = new ConsumerThread(resource);
p1.start();
p2.start();
p3.start();
c1.start();
//c2.start();
//c3.start();
}
}
/**
* 公共資源類
* @author
*
*/
class Resource{//重要
//當前資源數量
private int num = 0;
//資源池中允許存放的資源數目
private int size = 10;
/**
* 從資源池中取走資源
*/
public synchronized void remove(){
if(num > 0){
num--;
System.out.println("消費者" + Thread.currentThread().getName() +
"消耗一件資源," + "當前執行緒池有" + num + "個");
notifyAll();//通知生產者生產資源
}else{
try {
//如果沒有資源,則消費者進入等待狀態
wait();
System.out.println("消費者" + Thread.currentThread().getName() + "執行緒進入等待狀態");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 向資源池中新增資源
*/
public synchronized void add(){
if(num < size){
num++;
System.out.println(Thread.currentThread().getName() + "生產一件資源,當前資源池有"
+ num + "個");
//通知等待的消費者
notifyAll();
}else{
//如果當前資源池中有10件資源
try{
wait();//生產者進入等待狀態,並釋放鎖
System.out.println(Thread.currentThread().getName()+"執行緒進入等待");
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
/**
* 消費者執行緒
*/
class ConsumerThread extends Thread{
private Resource resource;
public ConsumerThread(Resource resource){
this.resource = resource;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.remove();
}
}
}
/**
* 生產者執行緒
*/
class ProducerThread extends Thread{
private Resource resource;
public ProducerThread(Resource resource){
this.resource = resource;
}
@Override
public void run() {
//不斷地生產資源
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.add();
}
}
}
方式二:lock和condition的await、signalAll
package producerConsumer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 使用Lock 和 Condition解決生產者消費者問題
* @author tangzhijing
*
*/
public class LockCondition {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition producerCondition = lock.newCondition();
Condition consumerCondition = lock.newCondition();
Resource2 resource = new Resource2(lock,producerCondition,consumerCondition);
//生產者執行緒
ProducerThread2 producer1 = new ProducerThread2(resource);
//消費者執行緒
ConsumerThread2 consumer1 = new ConsumerThread2(resource);
ConsumerThread2 consumer2 = new ConsumerThread2(resource);
ConsumerThread2 consumer3 = new ConsumerThread2(resource);
producer1.start();
consumer1.start();
consumer2.start();
consumer3.start();
}
}
/**
* 消費者執行緒
*/
class ConsumerThread2 extends Thread{
private Resource2 resource;
public ConsumerThread2(Resource2 resource){
this.resource = resource;
//setName("消費者");
}
public void run(){
while(true){
try {
Thread.sleep((long) (1000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.remove();
}
}
}
/**
* 生產者執行緒
* @author tangzhijing
*
*/
class ProducerThread2 extends Thread{
private Resource2 resource;
public ProducerThread2(Resource2 resource){
this.resource = resource;
setName("生產者");
}
public void run(){
while(true){
try {
Thread.sleep((long) (1000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.add();
}
}
}
/**
* 公共資源類
* @author tangzhijing
*
*/
class Resource2{
private int num = 0;//當前資源數量
private int size = 10;//資源池中允許存放的資源數目
private Lock lock;
private Condition producerCondition;
private Condition consumerCondition;
public Resource2(Lock lock, Condition producerCondition, Condition consumerCondition) {
this.lock = lock;
this.producerCondition = producerCondition;
this.consumerCondition = consumerCondition;
}
/**
* 向資源池中新增資源
*/
public void add(){
lock.lock();
try{
if(num < size){
num++;
System.out.println(Thread.currentThread().getName() +
"生產一件資源,當前資源池有" + num + "個");
//喚醒等待的消費者
consumerCondition.signalAll();
}else{
//讓生產者執行緒等待
try {
producerCondition.await();
System.out.println(Thread.currentThread().getName() + "執行緒進入等待");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}finally{
lock.unlock();
}
}
/**
* 從資源池中取走資源
*/
public void remove(){
lock.lock();
try{
if(num > 0){
num--;
System.out.println("消費者" + Thread.currentThread().getName()
+ "消耗一件資源," + "當前資源池有" + num + "個");
producerCondition.signalAll();//喚醒等待的生產者
}else{
try {
consumerCondition.await();
System.out.println(Thread.currentThread().getName() + "執行緒進入等待");
} catch (InterruptedException e) {
e.printStackTrace();
}//讓消費者等待
}
}finally{
lock.unlock();
}
}
}
BlockingQueue
package producerConsumer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
//使用阻塞佇列BlockingQueue解決生產者消費者
public class BlockingQueueConsumerProducer {
public static void main(String[] args) {
Resource3 resource = new Resource3();
//生產者執行緒
ProducerThread3 p = new ProducerThread3(resource);
//多個消費者
ConsumerThread3 c1 = new ConsumerThread3(resource);
ConsumerThread3 c2 = new ConsumerThread3(resource);
ConsumerThread3 c3 = new ConsumerThread3(resource);
p.start();
c1.start();
c2.start();
c3.start();
}
}
/**
* 消費者執行緒
* @author tangzhijing
*
*/
class ConsumerThread3 extends Thread {
private Resource3 resource3;
public ConsumerThread3(Resource3 resource) {
this.resource3 = resource;
//setName("消費者");
}
public void run() {
while (true) {
try {
Thread.sleep((long) (1000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
}
resource3.remove();
}
}
}
/**
* 生產者執行緒
* @author tangzhijing
*
*/
class ProducerThread3 extends Thread{
private Resource3 resource3;
public ProducerThread3(Resource3 resource) {
this.resource3 = resource;
//setName("生產者");
}
public void run() {
while (true) {
try {
Thread.sleep((long) (1000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
}
resource3.add();
}
}
}
class Resource3{
private BlockingQueue resourceQueue = new LinkedBlockingQueue(10);
/**
* 向資源池中新增資源
*/
public void add(){
try {
resourceQueue.put(1);
System.out.println("生產者" + Thread.currentThread().getName()
+ "生產一件資源," + "當前資源池有" + resourceQueue.size() +
"個資源");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 向資源池中移除資源
*/
public void remove(){
try {
resourceQueue.take();
System.out.println("消費者" + Thread.currentThread().getName() +
"消耗一件資源," + "當前資源池有" + resourceQueue.size()
+ "個資源");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
34、.xml中配置什麼 監聽器,過濾器,welcome-file,servlet, 35、實現執行緒安全的i++; 1、利用synchronize; 2、利用reentranlock; 3、利用reentranwriteandreadlock; 4、利用atomicinteger和count.incrementAndGet. 36、快速失敗和安全失敗 快速失敗是利用迭代器時,如果有其他執行緒妄圖修改集合類/map類就丟擲快速失敗 安全失敗是拷貝一份
37 陣列在記憶體的具體實現?記憶體角度分析?那麼陣列屬於類嗎?分析 int[] a=new int[100]; 在堆中開闢一段100個int型的資料單元,a建立在棧區,a是這段記憶體的頭指標。 但是陣列不屬於類,但是實現了類的所有方法。 38 計算機網路簇
39 jvm反射和cglicb反射怎麼實現
40密碼加密
41 保留登入狀態有哪幾種方法,專案裡的實現? 保留登入狀態就是要獲取session,session的獲取方法一共有三種 42 mysql優化和sql語句優化,以及mysql的debug工具? mysql的優化從底層到頂:sql和索引優化,資料庫表,系統配置,硬體 max,limit,group by,order by是sql語句優化 索引建立在 1 欄位長度短2 離散程度大3 需要經常查詢和排序的 過多的索引 不僅會影響寫入效率,還會影響查詢效率 表的建立:1選擇最小的形式進行儲存 2 儘量使用簡單的形式,int比時間戳和char簡單 3 儘量少使用not null 4 少用text
43 spring 的事務? 事務分為兩種方式:一種是宣告式,一種是程式設計式 宣告式又分xml和註解 其中xml事務必須先實現txmanager和aop兩種
<!-- 配置事務管理器 -->配置一個bean,類名是datasourcetransactionmanager,注入了DataSource
<bean id="cityPickTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource_backend-product" />
</property>
</bean>
<!-- 配置事務傳播特性 -->注入上面的citypicktansactionmanager,然後對方法進行一個事務管理,記住事務管理的本質是在mysql操作的,即如果和資料庫無關的就無需進行事務操作,但是幾乎所有的後端的類都會和資料庫發生互動,所以理論上都需要考慮資料庫。一般對查的要求不高,所以使用support即可,如過要查的話,就使用required,可以用事務就用不用就算了。
<tx:advice id="cityPickAdvice" transaction-manager="cityPickTransactionManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="add*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="create*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="update*" propagation="NESTED"
rollback-for="Exception" />
<tx:method name="batchApply*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="save*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="delete*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="fetch*" propagation="SUPPORTS" read-only="true" />
<tx:method name="is*" propagation="SUPPORTS" read-only="true" />
<tx:method name="*_noTrans" propagation="NOT_SUPPORTED" />
<tx:method name="*byTran" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置參與事務的類 -->
<aop:config>
<aop:pointcut id="cityPickManagerMethod"
expression=" (
execution(* com.test.service.impl.CityPriceScheduleServiceImpl.*(..))
) " />
<aop:advisor advice-ref="cityPickAdvice" pointcut-ref="cityPickManagerMethod" />、、事務管理
</aop:config>
</beans>
44 什麼是hashcoede?hashcode的計算方法?為什麼要重寫equals時需要重寫hashcode? hashCode是jdk根據物件的地址或者字串或者數字算出來的int型別的數值。 31(31(31*h+v0)+v1)+v2… 迭乘 因為約定就是兩個相等的物件就必須擁有相同的hashcode。因為假設在equals中沒有重寫hashcode,那麼如果在hashmap中使用到這兩個物件,因為hashmap是將兩個相等的物件放在一個地方,而此時雖然物件A==B,但是沒有重寫hashcode,導致hashcode不等,從而導致將兩個相等的物件放在兩個不同的hashmap位置。 45 TCP和UDP的區別,TCP的報文結構,UDP的報文結構
tcp報文結構
源埠 目標埠
序列號 確認號
TCP首部長度 保留 SYN ACK FIN URG RST PSH 視窗大小
校驗和 緊急指標
選項
資料部分
udp報文結構
源埠 目標埠
UDP長度 UDP校驗和
資料
ip報文
版本 首部長度 服務型別 總長度
標識 標誌 片偏移
源地址
目標地址
長度可選欄位 填充
資料
46 http 的結構以及http1.0和http1.1,2.0區別 (1)連線方面 HTTP1.0使用非持久連線,即在非持久連線下,一個tcp連線只傳輸一個Web物件。每次請求和響應都需要建立一個單獨的連線,每次連線只是傳輸一個物件,嚴重影響客戶機和伺服器的效能。 HTTP1.1預設使用持久連線(然而,HTTP/1.1協議的客戶機和伺服器可以配置成使用非持久連線)在持久連線下,不必為每個Web物件的傳送建立一個新的連線,一個連線中可以傳輸多個物件。在一個TCP連線上可以傳送多個HTTP請求和響應,減少了建立和關閉連線的消耗和延遲。HTTP 1.1的持續連線,也需要增加新的請求頭來幫助實現,例如,Connection請求頭的值為Keep-Alive時,客戶端通知伺服器返回本次請求結果後保持連線;Connection請求頭的值為close時,客戶端通知伺服器返回本次請求結果後關閉連線。HTTP 1.1還提供了與身份認證、狀態管理和Cache快取等機制相關的請求頭和響應頭。 (2)快取方面 HTTP1.0中主要使用header裡的If-Modified-Since,Expires來做為快取判斷的標準 HTTP1.1則引入了更多的快取控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供選擇的快取頭來控制快取策略頻寬優化及網路連線的使用 (3)狀態碼 在HTTP1.1中新增了24個錯誤狀態響應碼,如409(Conflict)表示請求的資源與資源的當前狀態發生衝突;410(Gone)表示伺服器上的某個資源被永久性的刪除 (4)頻寬優化 HTTP 1.1支援只發送header資訊(不帶任何body資訊),如果伺服器認為客戶端有許可權請求伺服器,則返回100,否則返回401。客戶端如果接收到100,才開始把請求body傳送到伺服器。 這樣當伺服器返回401的時候,客戶端就可以不用傳送請求body了,節約了頻寬。 (5)Host頭 HTTP1.0中認為每臺伺服器都繫結一個唯一的IP地址,因此,請求訊息中的URL並沒有傳遞主機名(hostname)。但隨著虛擬主機技術的發展,在一臺物理伺服器上可以存在多個虛擬主機(Multi-homed Web Servers),並且它們共享一個IP地址。 HTTP1.1的請求訊息和響應訊息都應支援Host頭域,且請求訊息中如果沒有Host頭域會報告一個錯誤(400 Bad Request)。 HTTP1.1 VS HTTP2.0 (1)多路複用: HTTP/1.1協議中,瀏覽器客戶端在同一時間針對同一域名的請求有一定資料限制。超過限制數目的請求會被阻塞。 HTTP2.0使用了多路複用的技術,做到同一個連線併發處理多個請求,而且併發請求的數量比HTTP1.1大了好幾個數量級。 當然HTTP1.1也可以多建立幾個TCP連線,來支援處理更多併發的請求,但是建立TCP連線本身也是有開銷的。 TCP連線有一個預熱和保護的過程,先檢查資料是否傳送成功,一旦成功過,則慢慢加大傳輸速度。因此對應瞬時併發的連線,伺服器的響應就會變慢。所以最好能使用一個建立好的連線,並且這個連線可以支援瞬時併發的請求。 (2)首部壓縮: HTTP1.1不支援header資料的壓縮,HTTP2.0使用HPACK演算法對header的資料進行壓縮,這樣資料體積小了,在網路上傳輸就會更快。 (3)伺服器推送: 當我們對支援HTTP2.0的web server請求資料的時候,伺服器會順便把一些客戶端需要的資源一起推送到客戶端,免得客戶端再次建立連線傳送請求到伺服器端獲取。這種方式非常合適載入靜態資源。 47 Linux下建立一個檔案用什麼命令,修改許可權使用什麼命令,修改所有者使用什麼命令?檢視網路連通?
48講講http協議,輸入一個網址到瀏覽器呈現出介面的過程是什麼樣子的? 在我們點選一個網址,到它能夠呈現在瀏覽器中,展示在我們面前,這個過程中,電腦裡,網路上,究竟發生了什麼事情。
伺服器啟動監聽模式
客戶端瀏覽器傳送請求
- 解析URL
- 輸入的是 URL 還是搜尋的關鍵字 當協議或主機名不合法時,瀏覽器會將位址列中輸入的文字傳給預設的搜尋引擎。大部分情況下,在把文字傳遞給搜尋引擎的時候,URL會帶有特定的一串字元,用來告訴搜尋引擎這次搜尋來自這個特定瀏覽器。 3. 轉換非 ASCII 的 Unicode 字元 瀏覽器檢查輸入是否含有不是 a-z, A-Z,0-9, - 或者 . 的字元 這裡主機名是 google.com ,所以沒有非ASCII的字元;如果有的話,瀏覽器會對主機名部分使用 Punycode 編碼
4. 檢查 HSTS 列表 瀏覽器檢查自帶的“預載入 HSTS(HTTP嚴格傳輸安全)”列表,這個列表裡包含了那些請求瀏覽器只使用HTTPS進行連線的網站 5. dns查詢
6. ARP 過程 要想傳送 ARP(地址解析協議)廣播,我們需要有一個目標 IP 地址,同時還需要知道用於傳送 ARP 廣播的介面的 MAC 地址。 首先查詢 ARP 快取,如果快取命中,我們返回結果:目標 IP = MAC 如果快取沒有命中: 檢視路由表,看看目標 IP 地址是不是在本地路由表中的某個子網內。是的話,使用跟那個子網相連的介面,否則使用與預設閘道器相連的介面。 查詢選擇的網路介面的 MAC 地址 我們傳送一個二層( OSI 模型 中的資料鏈路層)ARP 請求: ARP Request: Sender MAC: interface:mac:address:here Sender IP: interface.ip.goes.here Target MAC: FF:FF:FF:FF:FF:FF (Broadcast) Target IP: target.ip.goes.here 根據連線主機和路由器的硬體型別不同