同步是一種對共享資源的訪問方式。當多個資源須要訪問同一個互斥資源時,他們須要以某種順序來確保該資源在某個時刻只能有一個線程對其使用。html
異步是一種非阻塞方式。一個線程對對象的操做時,沒必要關心其餘線程的狀態或行爲,也沒必要等到方法處理完成返回後才進行以後的操做。前端
同步的實現方式:synchronized關鍵字(同步代碼塊、同步方法),可是系統開銷代價大,可能發生死鎖java
同一操做做用於不一樣的對象,能夠有不一樣的解釋,產生不一樣的執行結果。web
舉例:「電腦上的F1按鍵,當不打開任何文件點擊F1顯示的是系統的幫助文檔,當打開word文檔點擊F1顯示的是word文檔的幫助,同一個按鈕可是能實現不一樣的處理方式。」spring
除了代碼的複用性外,還能夠解決項目中緊耦合的問題,提升程序的可擴展性編程
實現條件:子類Child繼承父類Parent,能夠編寫一個指向子類的父類類型引用,該引用既能夠處理父類對象,也能夠處理子類對象。數組
繼承:在多態中必須存在有繼承關係的子類和父類。public class Child extends Parent{}瀏覽器
重寫:子類對父類中某些方法進行從新定義,在調用這些方法時就會調用子類的方法。(重寫方法能夠,即不改變函數名;重載不能夠,如Parent裏是fun1(),Child裏是fun1(String a))安全
向上轉型:在多態中須要將子類的引用賦給父類對象,只有這樣該引用纔可以具有調用父類的方法和子類的方法。Parent p=new Child(); 服務器
若子類重寫了父類中的某些方法,在調用該些方法的時候,一定是使用子類中定義的這些方法(動態鏈接、動態調用)。
實現形式:
繼承:在父類和繼承該父類的一個或多個子類對某些方法的重寫,多個子類對同一方法的重寫能夠表現出不一樣的行爲。
接口:指向接口的引用必須是指定這實現了該接口的一個類的實例程序,在運行時,根據對象引用的實際類型來執行對應的方法。
接口能夠是多繼承多實現,所以具備更好的靈活性
例子:
public class A { public String show(D obj) { return ("A and D"); } public String show(A obj) { return ("A and A"); } } public class B extends A{ public String show(B obj){ return ("B and B"); } public String show(A obj){ return ("B and A"); } } public class C extends B{ } public class D extends B{ } public class Test { public static void main(String[] args) { A a1 = new A(); A a2 = new B(); B b = new B(); C c = new C(); D d = new D(); System.out.println("1--" + a1.show(b)); System.out.println("2--" + a1.show(c)); System.out.println("3--" + a1.show(d)); System.out.println("4--" + a2.show(b)); System.out.println("5--" + a2.show(c)); System.out.println("6--" + a2.show(d)); System.out.println("7--" + b.show(b)); System.out.println("8--" + b.show(c)); System.out.println("9--" + b.show(d)); } } //輸出 1--A and A 2--A and A 3--A and D 4--B and A 5--B and A 6--A and D 7--B and B 8--B and B 9--A and D
當超類對象引用變量引用子類對象時,被引用對象的類型而不是引用變量的類型決定了調用誰的成員方法,可是這個被調用的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法,可是它仍然要根據繼承鏈中方法調用的優先級來確認方法,該優先級爲:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
即如a2.show(c):a2是A類型的引用變量,在A類中沒有找到show(C),所以查找A的超類中的show(C);可是A沒有超類,所以查找this.show((super)O),C的超類爲A、B,那麼能夠在A中找到show(A obj)。同時因爲a2是B類的一個引用且B類重寫了show(A obj),所以最終會調用子類B類的show(A obj)方法。
HashMap是一個用於存儲key-value鍵值對的集合,每一個鍵值對也叫作Entry。這些Entry分散存儲在一個數組當中,這個數組就是HashMap的主幹。
內部存儲結構:默認Entry數組的大小爲16,而Entry類包含一個類型爲Entry的next變量,所以至關於一個鏈表,全部hash值相同(即產生了衝突)的key會存儲在同一個鏈表。
自動擴容機制:當元素個數達到loadFactor後會擴大數組的大小,使即便數據量很大時,get()、put()、remove()等方法的效率都不會下降(rehash)
transient Entry<K,V>[] table; static class Entry<K,V> implements Map.Entry<K,V>{ final K key; V value; Entry<K,V> next; int hash; }
爲何HashMap線程不安全?(併發執行put操做時會引發死循環)
若是多個線程同時使用put方法添加元素,並且假設正好存在兩個put的key發生了碰撞(hash值同樣),那麼根據HashMap的實現,這兩個key會添加到數組的同一個位置,這樣最終就會發生其中一個線程的put的數據被覆蓋。
若是多個線程同時檢測到元素個數超過數組大小*loadFactor,這樣就會發生多個線程同時對Node數組進行擴容,都在從新計算元素位置以及複製數據,可是最終只有一個線程擴容後的數組會賦給table,也就是說其餘線程的都會丟失,而且各自線程put的數據也丟失。
如何線程安全的使用HashMap?
Hashtable:使用synchronized將整個hash表鎖住,效率低下。即全部的方法都加上了synchronized關鍵字,那麼當一個線程訪問Hashtable的同步方法時,其餘線程若是也要訪問同步方法,會被阻塞住。
ConcurrentHashMap(性能最優):經過鎖分離,由一個HashEntry數組和多個Segment(默認16個)組成,每一個Segment中又包含多個HashEntry列表數組。
每一個segment都擁有一個鎖,當進行寫操做時,只須要鎖定一個segment,而其它segment中的數據是能夠訪問的
SynchronizedMap:調用synchronizedMap()方法後會返回一個SynchronizedMap類的對象,而在SynchronizedMap類中使用了synchronized關鍵字來保證對Map的操做是線程安全的。
final,finally,finalize
關鍵字,若是一個類被聲明爲final,那麼它不能再派生出新的子類,不能做爲父類被繼承。一個類不能同時被聲明爲abstract和final
在異常處理時提供finally塊來執行任何清除操做,若拋出一個異常,那麼相匹配的catch子句就會執行,而後控制會進入finally塊
finalize方法名,在垃圾收集器將對象從內存中清除出去以前作必要的清理工做。是在Object類中定義的,所以全部的類都繼承了它。
int,Integer
int是基礎數據類型,屬於數據,不屬於類,天然也不屬於object的子類,沒法使用相關方法
Integer是其包裝類,包裝類爲了在各類類型間轉化,經過各類方法的調用,不然沒法直接經過變量轉化。
如int a=0;String b=Integer.toString(a); && List<Integer> nums;
裝箱,拆箱
裝箱就是自動將基本數據類型轉換爲包裝器類型
拆箱就是自動將包裝器類型裝換爲基本數據類型
Integer a = Integer.valueOf(123); //裝箱 int b = a.intValue(); //拆箱
String,StringBuilder,StringBuffer
String適用於少許的字符串操做,是字符串常量。String對象建立後不能夠改變,對String的操做其實是不斷建立和回收的過程,執行速度慢。
StringBuffer適用於單線程下的在字符串緩衝區進行大量的操做的狀況下。線程不安全,字符串變量
StringBuffer適用於多線程下的在字符串緩衝區進行大量的操做的狀況下。StringBuffer對象在字符串緩衝區被多個線程使用時,可使用synchronized關鍵字,可以保證線程安全。字符串變量
class,struct
class是面向對象程序設計實現信息封裝的基礎,每一個類包含數聽說明和一組操做數據或傳遞信息的函數,類的實例稱爲對象。
struct是值類型數據結構,使得一個單一變量能夠存儲各類數據類型得相關數據
class的默認成員訪問方式是private,struct的是public
堆棧的空間有限,對於具備大量邏輯的對象,建立類比建立結構好一些;而如點、矩形、顏色這類輕量對象,此時結構的成本更低
在表現抽象和多級別的對象層次時,類更好;而當該類型只是一些數據時,結構更好。
抽象類和接口
抽象類是能夠有私有方法或私有變量的,子類必須實現抽象類中的抽象方法,若是有未實現的,那麼子類也必須用 abstract 修飾
接口是公開的,裏面的方法默認public abstract,裏面不能有私有的方法或變量。不能是 static,接口中的方法也不容許子類覆寫,抽象類中容許有static 的方法。接口中的變量必須用 public static final 修飾,而且須要給出初始值。因此實現類不能從新定義,也不能改變其值。
抽象類只能被繼承一次,但能夠實現多個接口;但接口只能夠繼承一個或多個其它接口
接口和抽象類必須實現其中全部的方法,抽象類中若是有未實現的抽象方法,那麼子類也須要定義爲抽象類。抽象類中能夠有非抽象的方法
interface Alram { void alarm(); } abstract class Door { void open(); void close(); } class AlarmDoor extends Door implements Alarm { void oepn() { //.... } void close() { //.... } void alarm() { //.... } }
因爲Door的open() 、close()和alarm()根本就屬於兩個不一樣範疇內的行爲,alarm()屬於門的附加功能。若是都放在抽象類裏,那麼全部繼承這個抽象類的子類都具有報警功能,不成立;若是都放在接口裏,那麼須要用到報警功能的類就須要實現接口中的open()和close(),可是若是不是門,就不具備這個屬性。沒法擴展
重載overload和重寫override
重寫:方法名、參數、返回值相同;子類方法不能縮小父類方法的訪問權限;子類方法不能拋出比父類方法更多的異常;存在子類和父類之間;被定義爲final不能被重寫
重載:參數類型、個數、順序至少有一個不相同;不能重載只有返回值不一樣的方法名;存在於父類和子類、同類中
session和cookie(用於完成會話跟蹤)
cookie是web服務器發送給瀏覽器的一塊信息,瀏覽器會在本地文件中給每個web服務器存儲cookie
不管客戶端和瀏覽器如何設置,session都能正常工做,客戶端能夠選擇禁用cookie。而session仍然能夠工做,由於客戶端沒法禁用服務端的session。
cookie的數據存儲在客戶端,session的數據存儲在服務器上
cookie不是很安全,別人能夠經過分析存放在本地的cookie並進行cookie欺騙,考慮到安全應該使用session
session會在必定時間內保存在服務器上,當訪問增多時,會影響服務器的性能.考慮到服務器性能,應當使用cookie.
equals,==
值類型(int,char,long,boolean等)都是經過==判斷相等,判斷引用所指的對象是不是同一個
equals是Object的成員函數,用於判斷對象的等價性
list,set(都繼承自Collection接口)
list中元素有順序放入,元素可重複。檢索效率高,但插入刪除元素效率低
set中元素無順序放入,不可重複,重複元素將會被覆蓋。元素在set中的位置由該元素的hashcode決定,位置固定。
collection,map
collection是對象集合,包含list和set。其中list是有序且可重複的,set是無序且不可重複的。
map是鍵值對的集合,不容許key重複。包括hashmap,hashtable,currenthashmap
Arraylist,LinkedList,Vector
當須要對數據進行屢次訪問的狀況下選用ArrayList,當須要對數據進行屢次增長刪除修改時採用LinkedList。
ArrayList實現基於動態數組的數據結構,地址連續
LinkedList實現基於鏈表的數據結構,地址任意,在開闢新空間時不須要等一個連續的地址
Vector相似數組存儲在內存中,線程同步,適合查找
封裝,繼承,多態和抽象
封裝給對象提供了隱藏內部特性和行爲的能力,對象提供一些能被其餘對象訪問的方法來改變它內部的數據
繼承給對象提供了從基類獲取字段和方法的能力
多態是編程語言給不一樣的底層數據類型作相同的接口展現的一種能力
抽象是把想法從具體的實例中分離出來的步驟,即把類的行爲和實現細節分離開
進程是指運行中的應用程序,每一個進程都有本身獨立的地址空間(內存空間)。是程序運行和資源分配的基本單位
線程是進程中的一個實體,便是一個輕量級的進程。是被系統獨立調度和分派的基本單位,線程本身不擁有系統資源,只擁有一點在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的所有資源。是CPU調度和分配的基本單位
特色:由進程建立(寄生在進程);一個進程能夠擁有多個線程(多線程,並非併發執行,而是交替佔用CPU資源);擁有新建、就緒、運行、阻塞(線程因爲某些緣由放棄CPU使用權,暫時中止運行。分爲等待阻塞、同步阻塞、其餘阻塞)、死亡狀態。
線程池的好處?
限定線程的個數,不會致使因爲線程過多致使系統運行緩慢或崩潰
線程池每次都不須要建立和銷燬,節約了資源
線程池不須要每次都去建立,響應時間更快
如何實現java多線程?
extends Thread類:實際上是一個實現了Runnable接口的實例,啓動線程的惟一方法就是經過調用Thread類的start()方法
implement Runnable接口:推薦,接口方式不影響當前類繼承其餘類,且能夠實現資源共享。實現run()
implement Callable接口:重寫call方法
如何實現java多線程同步?
synchronized關鍵字。java中每一個對象都有一個鎖,當一個線程調用一段synchronized代碼時,須要先獲取這個鎖,而後去執行相應的代碼,執行結束後釋放鎖。
同步方法:public synchronized void mutiThreadAccess();
同步代碼塊:synchronized(syncObject){ }
wait和notify方法,與synchronized配合使用。在synchronized代碼被執行期間,可使用wait方法釋放該對象的鎖,進入等待狀態,並能夠調用notify方法或者notifyAll方法通知正在等待的其餘線程。notify方法爲通知等待隊列中的第一個等待線程,而notifyAll方法則是喚醒全部等待線程,並容許他們去競爭獲取鎖。
lock方法。JDK 5新增了Lock接口和他的一個實現類ReentrantLock(重入鎖),阻塞的方式獲取鎖
終止線程的方法?
stop(),會釋放已經鎖定的全部監視資源,但程序容易進入一個不一致的狀態
suspend(),容易發生死鎖,但不會釋放鎖
自行結束進入DEAD狀態,即,執行完run(),設置一個flag變量
interrupt()打算阻塞拋出異常,安全退出
多線程的上下文切換?
CPU控制權由一個正在運行的線程切換到另外一個就緒並等待獲取CPU執行權的線程的過程。
什麼是死鎖?
多個線程在執行過程當中,因爭奪資源而致使的一種互相等待的狀況
互斥:一個資源每次只能被一個進程所使用
請求和保持:一個進程因請求資源而阻塞,對已得到的資源保持不放
不剝奪:進程已得到的資源,在未使用完成以前,不能強行剝奪
循環等待:若干線程之間造成一種頭尾相接的循環等待的資源獲取關係
常見的runtime exception
NullPointerException - 空指針引用異常
ClassCastException - 類型強制轉換異常。
IllegalArgumentException - 傳遞非法參數異常。
ArithmeticException - 算術運算異常
ArrayStoreException - 向數組中存放與聲明類型不兼容對象異常
IndexOutOfBoundsException - 下標越界異常
NegativeArraySizeException - 建立一個大小爲負數的數組錯誤異常
NumberFormatException - 數字格式異常
SecurityException - 安全異常
UnsupportedOperationException - 不支持的操做異常
Exception,Error,runtime Exception,通常異常有什麼異同?
public void test() { System.out.println(test2()); } public int test() { int b = 20; try { System.out.println("try block"); return b += 80; } catch (Exception e) { System.out.println("catch block"); } finally { System.out.println("finally block"); if (b > 25) { System.out.println("b>25, b = " + b); } return 200; } } //try block //finally block //b>25, b = 100 //200
finally塊的語句在try或catch中的return語句執行以後 返回 以前執行且finally裏的修改語句 可能影響也可能不影響 try或catch中 return已經肯定的返回值,若finally裏也有return語句則覆蓋try或catch中的return語句直接返回。
反射的用途及實現
在運行狀態中,容許改變程序結構或變量類型,這種語言稱爲動態語言。雖然java不屬於動態語言,但具備一個動態相關機制:reflection,便可以在運行時加載、探知、使用編譯期間徹底未知的class。
即在JVM運行期間經過查找到相應的類,經過類獲取其屬性以及方法來創造對象。
例如經過反射構造類:
1).Class clazz=Class.formName(「com.tlc.Person」);#經過class的靜態方法獲取對象
2).使用newInstance()或者newInstance(Object….params)建立實例
Java AIO、NIO、BIO?
一個IO操做能夠分爲兩個步驟:發起IO請求和實際的IO操做
首先理清楚阻塞的概念:阻塞調用是指調用結果返回以前,當前線程會被掛起,函數只有在獲得結果以後纔會返回。
非阻塞是指不能當即獲得結果以前,該函數只有在獲得結果以後纔會返回。參考一篇博文,以爲這個概念會很清晰「你先幹,我先看看有沒有其餘事,你完事了告訴我」
阻塞與非阻塞IO區別在於第一步:發起IO請求是否會被阻塞,若阻塞直到完成就是阻塞IO.
同步與異步IO區別在於第二個步驟是否阻塞:針對應用程序和內核的交互而言,同步就是用戶進程觸發IO操做並等待或輪詢地去查看IO操做是否就緒;異步就是用戶進程觸發IO操做之後便開始作本身的事情,而當IO操做已經完成的時候會獲得IO完成的通知。
同步和異步是目的,阻塞和非阻塞是實現方式
再來進行組合:
服務器實現模式爲一個鏈接一個線程,即客戶端有鏈接請求時服務器端就須要啓動一個線程進行處理,若是這個鏈接不作任何事情會形成沒必要要的線程開銷,固然能夠經過線程池機制改善。
適用於鏈接數目比較小且固定的架構
服務器實現模式爲一個請求一個線程,即客戶端發送的鏈接請求都會註冊到多路複用器上,多路複用器輪詢到鏈接有I/O請求時才啓動一個線程進行處理。
適用於鏈接數目多且鏈接比較短(輕操做)的架構,好比聊天服務器
服務器實現模式爲一個有效請求一個線程,客戶端的I/O請求都是由OS先完成了再通知服務器應用去啓動線程進行處理.
適用於鏈接數目多且鏈接比較多(重操做)的架構,好比相冊服務器
異步不會再去區分阻塞非阻塞,對於用戶進程,接到異步通知後,就直接操做進程用戶態空間裏的數據便可。
一個 請求匹配前端控制器C 的 請求映射路徑,WEB容器 將該請求轉交給 前端控制器處理
前端控制器接收到請求後,根據 請求信息 交給 處理器映射器
處理器映射器 根據用戶的url請求 查找匹配該url的Handler,並返回處理器執行鏈
前端控制器 再請求 處理器適配器M 調用相應的處理器 執行相應的Handler,並返回ModelAndView給前端控制器
前端控制器 將 ModelAndView 請求 視圖解析器V 解析,返回具體view對象
前端控制器 對view進行渲染
前端控制器 將頁面響應給用戶
JSP運行原理
每一個JSP頁面在第一次被訪問時, JSP引擎將它翻譯成一個 Servlet 源程序, 接着再把這個 Servlet 源程序編譯成 Servlet 的 class 類文件.
而後再由WEB容器(Servlet引擎)像調用普通Servlet程序同樣的方式來裝載和解釋執行這個由JSP頁面翻譯成的Servlet程序。
servlet的理解?
Servlet是能夠運行在服務器上的小型Java程序,它和通常的java程序的區別是是:能夠經過HTTP協議接收和響應來自Web客戶端的請求。
servlet的生命週期?
當用戶第一次訪問Servlet的時候,服務器會建立一個Servlet的實例,那麼Servlet中的init方法就會執行。任何一次請求都會建立一個線程訪問Servlet中的service方法,根據請求的不一樣方式調用不一樣的doXXX()方法(doGet()/doPost())。當Servlet從服務器中移除或者關閉服務器,Servlet的實例就會被銷燬,那麼destory()方法就會執行
servlet中forward和redirect的區別?
請求的轉發只發出了一次請求, 而重定向則發出了兩次請求。
所以請求的轉發時地址欄爲初次發出請求的地J址;而請求的重定向時地址欄再也不是初次發出的請求地址,地址欄爲最後響應的那個地址。
請求的轉發只能轉發給當前WEB應用的資源;請求的重定向能夠重定向到任何資源。