天天看點

一些細節記錄

Access-Control-Allow-Origin跨域

1.Redis 的分布式鎖實作。Redis 的分布式鎖都是基于一個指令 -- SETNX,也就是 SET IF NOT EXIST,如果不存在就寫入。

從 Redis 2.6.12 版本開始,Redis 的 SET 指令直接直接設定 NX 和 EX 屬性,NX 即附帶了 SETNX 資料,key 存在就無法插入,EX 是過期屬性,可以設定過期時間。這樣一個指令就能原子的完成加鎖和設定過期時間。

2.var a;var b=!!a;

a預設是undefined。!a是true,!!a則是false,是以b的值是false,而不再是undefined,也非其它值,主要是為後續判斷提供便利。

!!一般用來将後面的表達式強制轉換為布爾類型的資料(boolean),也就是隻能是true或者false;

3.Spring事務機制

事務注解方式: @Transactional

事物傳播行為介紹:

@Transactional(propagation=Propagation.REQUIRED)

如果有事務, 那麼加入事務, 沒有的話建立一個(預設情況下)

@Transactional(propagation=Propagation.REQUIRES_NEW)

不管是否存在事務,都建立一個新的事務,原來的挂起,新的執行完畢,繼續執行老的事務

@Transactional(propagation=Propagation.SUPPORTS)

如果其他bean調用這個方法,在其他bean中聲明事務,那就用事務.如果其他bean沒有聲明事務,那就不用事務.

@Transactional(propagation=Propagation.NOT_SUPPORTED)

容器不為這個方法開啟事務

@Transactional(propagation=Propagation.MANDATORY)

必須在一個已有的事務中執行,否則抛出異常

@Transactional(propagation=Propagation.NEVER)

必須在一個沒有的事務中執行,否則抛出異常(與Propagation.MANDATORY相反)

事物逾時設定:

@Transactional(timeout=30) //預設是30秒

事務隔離級别:

@Transactional(isolation = Isolation.READ_UNCOMMITTED)

讀取未送出資料(會出現髒讀, 不可重複讀) 基本不使用

@Transactional(isolation = Isolation.READ_COMMITTED)

讀取已送出資料(會出現不可重複讀和幻讀)

@Transactional(isolation = Isolation.REPEATABLE_READ)

可重複讀(會出現幻讀)

@Transactional(isolation = Isolation.SERIALIZABLE)

串行化

MYSQL: 預設為REPEATABLE_READ級别

SQLSERVER: 預設為READ_COMMITTED

髒讀:一個事務讀取了另一個事務未送出的資料。事務A:張三妻子給張三轉賬100元。事務B:張三查詢餘額。事務A轉賬後(還未送出),事務B查詢多了100元。事務A由于某種問題,比如逾時,進行復原。事務B查詢到的資料是假資料。髒讀本質上是讀寫操作的沖突,解決辦法是寫完之後再讀。

不可重複讀:一個事務兩次讀取同一個資料,兩次讀取的資料不一緻。事務A:張三妻子給張三轉賬100元。事務B:張三兩次查詢餘額。事務B第一次查詢餘額,事務A還沒有轉賬,第二次查詢餘額,事務A已經轉賬了,導緻一個事務中,兩次讀取同一個資料,讀取的資料不一緻。不可重複讀本質上是讀寫操作的沖突,解決辦法是讀完再寫。

幻象讀:一個事務兩次讀取一個範圍的記錄,兩次讀取的記錄數不一緻。事務A:張三妻子兩次查詢張三有幾張銀行卡。事務B:張三新辦一張銀行卡。事務A第一次查詢銀行卡數的時候,張三還沒有新辦銀行卡,第二次查詢銀行卡數的時候,張三已經新辦了一張銀行卡,導緻兩次讀取的銀行卡數不一樣。幻象讀本質上是讀寫操作的沖突,解決辦法是讀完再寫。

4.final

final 修飾的類不能被繼承。

final 修飾的方法不能被子類重寫。

final 修飾的變量(成員變量或局部變量)即成為常量,隻能指派一次。

final 修飾的成員變量必須在聲明的同時指派,如果在聲明的時候沒有指派,那麼隻有 一次指派的機會,而且隻能在構造方法中顯式指派,然後才能使用。

final 修飾的局部變量可以隻聲明不指派,然後再進行一次性的指派。

5.初始化

虛拟機中嚴格規定了有且隻有5種情況必須對類進行初始化。 

1、執行new、getstatic、putstatic和invokestatic指令; 

2、使用reflect對類進行反射調用; 

3、初始化一個類的時候,父類還沒有初始化,會事先初始化父類; 

4、啟動虛拟機時,需要初始化包含main方法的類; 

5、在JDK1.7中,如果java.lang.invoke.MethodHandler執行個體最後的解析結果REFgetStatic、REFputStatic、REF_invokeStatic的方法句柄,并且這個方法句柄對應的類沒有進行初始化;

============================================

類什麼時候才被初始化:

1)建立類的執行個體,也就是new一個對象

2)通路某個類或接口的靜态變量,或者對該靜态變量指派

3)調用類的靜态方法

4)反射(Class.forName("com.lyj.load"))

5)初始化一個類的子類(會首先初始化子類的父類)

6)JVM啟動時标明的啟動類,即檔案名和類名相同的那個類

隻有這6中情況才會導緻類的類的初始化。

 ​

6.redis,資料類型,分布式鎖,緩存擊穿

String(字元串) Hash(哈希) List(清單) Set(集合)  zset(sorted set:有序集合)

setnx

7.分布式事務怎麼保證 (用消息隊列保證)

8.dubbo遠端調用線程池的配置, 遠端調用協定 傳輸協定 反序列化協定。  調用過程

9.synchronized實作原理

Java對象頭和monitor是實作synchronized的基礎

10.Vector是ArrayList的多線程版本,HashTable是HashMap的多線程版本

Collections.synchronizedList,CopyOnWriteArrayList差別:

CopyOnWriteArrayList的寫操作性能較差,而多線程的讀操作性能較好。而Collections.synchronizedList的寫操作性能比CopyOnWriteArrayList在多線程操作的情況下要好很多,而讀操作因為是采用了synchronized關鍵字的方式,其讀操作性能并不如CopyOnWriteArrayList。是以在不同的應用場景下,應該選擇不同的多線程安全實作類。

Collections.synchronizedMap()與ConcurrentHashMap主要差別是:

Collections.synchronizedMap()和Hashtable一樣,實作上在調用map所有方法時,都對整個map進行同步,而ConcurrentHashMap的實作卻更加精細,它對map中的所有桶加了鎖。

是以,隻要要有一個線程通路map,其他線程就無法進入map,而如果一個線程在通路ConcurrentHashMap某個桶時,其他線程,仍然可以對map執行某些操作。

這樣,ConcurrentHashMap在性能以及安全性方面,明顯比Collections.synchronizedMap()更加有優勢。同時,同步操作精确控制到桶,是以,即使在周遊map時,其他線程試圖對map進行資料修改,也不會抛出ConcurrentModificationException。

11.ThreadLocal

ThreadLocal與線程同步機制不同,線程同步機制是多個線程共享同一個變量,而ThreadLocal是為每一個線程建立一個單獨的變量副本,故而每個線程都可以獨立地改變自己所擁有的變量副本,而不會影響其他線程所對應的副本。

ThreadLocal為什麼會記憶體洩漏?

每個Thread都有一個ThreadLocal.ThreadLocalMap的map,該map的key為ThreadLocal執行個體,它為一個弱引用,我們知道弱引用有利于GC回收。當ThreadLocal的key == null時,GC就會回收這部分空間,但是value卻不一定能夠被回收,因為他還與Current Thread存在一個強引用關系。由于存在這個強引用關系,會導緻value無法回收。如果這個線程對象不會銷毀那麼這個強引用關系則會一直存在,就會出現記憶體洩漏情況。是以說隻要這個線程對象能夠及時被GC回收,就不會出現記憶體洩漏。如果碰到線程池,那就更坑了。

那麼要怎麼避免這個問題呢?

在前面提過,在ThreadLocalMap中的setEntry()、getEntry(),如果遇到key == null的情況,會對value設定為null。當然我們也可以顯示調用ThreadLocal的remove()方法進行處理。

12.二叉樹的三種周遊方式

二叉樹有三種周遊方式:前序(父節點,左節點,右節點),中序(左節點,父節點,右節點),後序(左節點,右節點,父節點)

13.jvm調優

堆設定:

-Xms:初始堆大小

-Xmx:最大堆大小

-Xmn:新生代大小(通常為 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 個 Survivor 空間。實際可用空間為 = Eden + 1 個 Survivor,即 90%)

-XX:NewSize=n:設定年輕代大小

-XX:MaxNewSize=n:設定最大年輕代大小

-XX:NewRatio=n:設定年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)。設定為4,則年輕代與年老代所占比值為1:4,年輕代占整個堆棧的1/5

-XX:SurvivorRatio=n:年輕代中Eden區與兩個Survivor區的比值。注意Survivor區有兩個。如:8,表示一個Survivor區占整個年輕代的1/10

-XX:PermSize=n:設定持久代大小,一般為64M

-XX:MaxPermSize=n:設定最大持久代大小

-XX:MaxTenuringThreshold=0:設定垃圾最大年齡。如果設定為0的話,則年輕代對象不經過Survivor區,直接進入年老代。對于年老代比較多的應用,可以提高效率。如果将此值設定為一個較大值,則年輕代對象會在Survivor區進行多次複制,這樣可以增加對象再年輕代的存活時間,增加在年輕代即被回收的概論。

14.ArrayList,LinkedList

1.ArrayList是實作了基于動态數組的資料結構,LinkedList基于連結清單的資料結構。

2.對于随機通路get和set,ArrayList覺得優于LinkedList,因為LinkedList要移動指針。

3.對于新增和删除操作add和remove,LinedList比較占優勢,因為ArrayList要移動資料

15.java 代碼中如何避免記憶體洩露

記憶體洩露的定義:對于應用程式來說,當對象已經不再被使用,但是Java的垃圾回收器不能回收它們的時候,就産生了記憶體洩露。

未引用對象将會被垃圾回收器回收,而引用對象卻不會。未引用對象很顯然是無用的對象。然而,無用的對象并不都是未引用對象,有一些無用對象也有可能是引用對象,這部分對象正是記憶體洩露的來源。

怎樣阻止記憶體洩露?

1.使用List、Map等集合時,在使用完成後指派為null,或者使用弱引用類型WeakHashMap

2.使用大對象時,在用完後指派為null

3.目前已知的jdk1.6的substring()方法會導緻記憶體洩露

4.避免一些死循環等重複建立或對集合添加元素,撐爆記憶體

5.簡潔資料結構、少用靜态集合等

6.及時的關閉打開的檔案,socket句柄等

7.多關注事件監聽(listeners)和回調(callbacks),比如注冊了一個listener,當它不再被使用的時候,忘了登出該listener,可能就會産生記憶體洩露

16.Java對象的引用級别

強引用(StrongReference)

強引用是使用最普遍的引用。如果一個對象具有強引用,那垃圾回收器絕不會回收它。當記憶體空間不足,Java虛拟機甯願抛出OutOfMemoryError錯誤,使程式異常終止,也不會靠随意回收具有強引用的對象來解決記憶體不足的問題。

軟引用(SoftReference)

如果一個對象隻具有軟引用,則記憶體空間足夠,垃圾回收器就不會回收它;如果記憶體空間不足了,就會回收這些對象的記憶體。隻要垃圾回收器沒有回收它,該對象就可以被程式使用。軟引用可用來實作記憶體敏感的高速緩存(下文給出示例)。

軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛拟機就會把這個軟引用加入到與之關聯的引用隊列中。

弱引用(WeakReference)

弱引用與軟引用的差別在于:隻具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的記憶體區域的過程中,一旦發現了隻具有弱引用的對象,不管目前記憶體空間足夠與否,都會回收它的記憶體。不過,由于垃圾回收器是一個優先級很低的線程,是以不一定會很快發現那些隻具有弱引用的對象。

弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛拟機就會把這個弱引用加入到與之關聯的引用隊列中。

虛引用(PhantomReference)

“虛引用”顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用并不會決定對象的生命周期。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。

虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個差別在于:虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象的記憶體之前,把這個虛引用加入到與之關聯的引用隊列中。

程式可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否将要被垃圾回收。如果程式發現某個虛引用已經被加入到引用隊列,那麼就可以在所引用的對象的記憶體被回收之前采取必要的行動。

​​http://blog.51cto.com/zhangjunhd/53092​​

17.JDK動态代理和CGLIB代理生成的差別

JDK動态代理隻能對實作了接口的類生成代理,而不能針對類 。

CGLIB是針對類實作代理,主要是對指定的類生成一個子類,覆寫其中的方法 。

因為是繼承,是以該類或方法最好不要聲明成final ,final可以阻止繼承和多态。

18.SpringMVC 攔截器

攔截器接口-HandlerInterceptor

自定義的攔截器,需要繼承HandlerInterceptor接口,并且實作HandlerInterceptor中提供的三個方法:

1. preHandle 方法會在請求處理前被調用。這個方法傳回boolean值,如果傳回true則繼續往下執行,如果傳回false則中斷。

2. postHandle 方法會在請求處理後,繼續調用。

3. afterCompletion 方法會在視圖渲染之後調用。

19.Error和Exception的聯系

繼承結構:Error和Exception都是繼承于Throwable,RuntimeException繼承自Exception。

Error和RuntimeException及其子類稱為未檢查異常(Unchecked exception),其它異常成為受檢查異常(Checked Exception)。

Error和Exception的差別

Error類一般是指與虛拟機相關的問題,如系統崩潰,虛拟機錯誤,記憶體空間不足,方法調用棧溢出等。如java.lang.StackOverFlowError和Java.lang.OutOfMemoryError。對于這類錯誤,Java編譯器不去檢查他們。對于這類錯誤的導緻的應用程式中斷,僅靠程式本身無法恢複和預防,遇到這樣的錯誤,建議讓程式終止。

Exception類表示程式可以處理的異常,可以捕獲且可能恢複。遇到這類異常,應該盡可能處理異常,使程式恢複運作,而不應該随意終止異常。

運作時異常和受檢查的異常

Exception又分為運作時異常(Runtime Exception)和受檢查的異常(Checked Exception )。

RuntimeException:其特點是Java編譯器不去檢查它,也就是說,當程式中可能出現這類異常時,即使沒有用try……catch捕獲,也沒有用throws抛出,還是會編譯通過,如除數為零的ArithmeticException、錯誤的類型轉換、數組越界通路和試圖通路空指針等。處理RuntimeException的原則是:如果出現RuntimeException,那麼一定是程式員的錯誤。

受檢查的異常(IOException等):這類異常如果沒有try……catch也沒有throws抛出,編譯是通不過的。這類異常一般是外部錯誤,例如檔案找不到、試圖從檔案尾後讀取資料等,這并不是程式本身的錯誤,而是在應用環境中出現的外部錯誤。

throw 和 throws兩個關鍵字有什麼不同

throw 是用來抛出任意異常的,你可以抛出任意 Throwable,包括自定義的異常類對象;throws總是出現在一個函數頭中,用來标明該成員函數可能抛出的各種異常。如果方法抛出了異常,那麼調用這個方法的時候就需要處理這個異常。

20.String,StringBuilder,StringBuffer  (需要注意字元串常量池)

String:适用于少量的字元串操作的情況

StringBuilder:适用于單線程下在字元緩沖區進行大量操作的情況

StringBuffer:适用多線程下在字元緩沖區進行大量操作的情況

StringBuffer和StringBuilder可謂雙胞胎,StringBuilder是1.5新引入的,其前身就是StringBuffer。StringBuilder的效率比StringBuffer稍高,如果不考慮線程安全,StringBuilder應該是首選。另外,JVM運作程式主要的時間耗費是在建立對象和回收對象上。

(1) 在編譯階段就能夠确定的字元串常量,完全沒有必要建立String或StringBuffer對象。直接使用字元串常量的"+"連接配接操作效率最高。

(2) StringBuffer對象的append效率要高于String對象的"+"連接配接操作。

(3)不停的建立對象是程式低效的一個重要原因。那麼相同的字元串值能否在堆中隻建立一個String對象那。顯然拘留字元串能夠做到這一點,除了程式中的字元串常量會被JVM自動建立拘留字元串之外,調用String的intern()方法也能做到這一點。當調用intern()時,如果常量池中已經有了目前String的值,那麼傳回這個常量指向拘留對象的位址。如果沒有,則将String值加入常量池中,并建立一個新的拘留字元串對象。

javascript:void(0)

21.Spring加載類的注解有哪幾種?

(1)@Autowired

@Autowired可以對成員變量、方法和構造函數進行标注,來完成自動裝配的工作。 

(2)@Resource(JSR-250标準注解,推薦使用它來代替Spring專有的@Autowired注解)

Spring 不但支援自己定義的@Autowired注解,還支援幾個由JSR-250規範定義的注解,它們分别是@Resource、@PostConstruct以及@PreDestroy。

@Resource的作用相當于@Autowired,隻不過@Autowired按byType自動注入,而@Resource預設按 byName自動注入罷了。@Resource有兩個屬性是比較重要的,分别是name和type,Spring将@Resource注解的name屬性解析為bean的名字,而type屬性則解析為bean的類型。是以如果使用name屬性,則使用byName的自動注入政策,而使用type屬性時則使用byType自動注入政策。如果既不指定name也不指定type屬性,這時将通過反射機制使用byName自動注入政策。

@Component(不推薦使用)、@Repository、@Service、@Controller

22.過濾器和攔截器器差別?

一、filter基于filter接口中的doFilter回調函數,interceptor則基于Java本身的反射機制;

二、filter是依賴于servlet容器的,沒有servlet容器就無法回調doFilter方法,而interceptor與servlet無關;

三、filter的過濾範圍比interceptor大,filter除了過濾請求外通過通配符可以保護頁面、圖檔、檔案等,而interceptor隻能過濾請求,隻對action起作用,在action之前開始,在action完成後結束(如被 攔截,不執行action);

四、filter的過濾一般在加載的時候在init方法聲明,而interceptor可以通過在xml聲明是guest請求還 是user請求來辨識是否過濾;

五、interceptor可以通路action上下文、值棧裡的對象,而filter不能;

六、在action的生命周期中,攔截器可以被多次調用,而過濾器隻能在容器初始化時被調用一次

23.序列化問題

1.靜态變量不能被序列化

2.序列化可以被加密解密(RMI遠端過程調用位元組流的不安全性,是以可以模糊序列化資料),簽名認證

3.父類不序列化,子類序列化,反序列化得到的父類字段為對象為null,int為0

4.序列化id不同,無法互相序列化和反序列化

5.加Transient的字段不能被序列化

6.序列化兩次寫入一個檔案和一次寫入這個檔案,反序列化後兩個對象是相等的,存儲規則為持有第一次寫入檔案的引用,占用記憶體

7.對象的字段第一次寫入 然後序列化,再次對該字段指派再次序列化,反序列化取第一次序列化的 值,因為虛拟機根據引用關系知道已經有一個相同對象已經寫入檔案,是以隻儲存第二次寫的引用,是以讀取時,都是第一次儲存的對象。讀者在使用一個檔案多次 writeObject 需要特别注意這個問題。

8.序列化可以将代理放在流中

sublist 不能被序列化

static 不能被序列化

transient不能被序列化

24.BeanFactory和FactoryBean的差別