Java 基础总结。
?
1.為什么要用裝箱與拆箱
Java是面向對象語言。基本數據類型不具有面向對象的特性。
2.== 與 Equals方法有什么區別
== 用來判斷像個變量之間的值是否相等,變量分為基本數據類型對象與引用類型對象。
如果是基本數據類型變量直接比較而引用類型比較對應的引用內存的首地址。
equals 用來比較兩個對象長的是否一樣,判斷兩個對象某些特征是否一樣。
3.String 與 StringBuffer 區別? ?
String 是內容不可變得字符串。String 底層使用一個不可變得字符數組(Final chart[])
※ FInal如果修飾一個類就不能被繼承,如果修飾一個變量那么被賦值就不能再改變
StringBuffer與StringBuilder是內容可以改變的字符串。底層使用一個可變的字符數組。
4.StringBuffer與StringBuilder區別?
StringBuilder 是線程不安全的效率較高。
StringBuffer 是線程安全的效率較低、添加一個同步鎖。
最經典的拼接字符串.
1.String進行拼接,String c = "a" + "b";
2.StringBuffer與StringBuilder? 拼接。? 通過append進行拼接。
字符串池的優缺點:
優點:字符串池的優點避免相同字符串的創建節省內存,省去創建相同字符串的的時間提高性能
缺點:Jvm在常量池遍歷對象花費的時間,不過時間成本較少
/** * 情景一:字符串池 * JAVA虛擬機(JVM)中存在著一個字符串池,其中保存著很多String對象; * 并且可以被共享使用,因此它提高了效率。 * 由于String類是final的,它的值一經創建就不可改變。 * 字符串池由String類維護,我們可以調用intern()方法來訪問字符串池。 */ String s1 = "abc"; //↑ 在字符串池創建了一個對象 String s2 = "abc"; //↑ 字符串pool已經存在對象“abc”(共享),所以創建0個對象,累計創建一個對象 System.out.println("s1 == s2 : "+(s1==s2)); //↑ true 指向同一個對象, System.out.println("s1.equals(s2) : " + (s1.equals(s2))); //↑ true 值相等 //↑------------------------------------------------------over /** * 情景二:關于new String("") * */ String s3 = new String("abc"); //↑ 創建了兩個對象,一個存放在字符串池中,一個存在與堆區中; //↑ 還有一個對象引用s3存放在棧中 String s4 = new String("abc"); //↑ 字符串池中已經存在“abc”對象,所以只在堆中創建了一個對象 System.out.println("s3 == s4 : "+(s3==s4)); //↑false s3和s4棧區的地址不同,指向堆區的不同地址; System.out.println("s3.equals(s4) : "+(s3.equals(s4))); //↑true s3和s4的值相同 System.out.println("s1 == s3 : "+(s1==s3)); //↑false 存放的地區多不同,一個棧區,一個堆區 System.out.println("s1.equals(s3) : "+(s1.equals(s3))); //↑true 值相同 //↑------------------------------------------------------over /** * 情景三: * 由于常量的值在編譯的時候就被確定(優化)了。 * 在這里,"ab"和"cd"都是常量,因此變量str3的值在編譯時就可以確定。 * 這行代碼編譯后的效果等同于: String str3 = "abcd"; */ String str1 = "ab" + "cd"; //1個對象 String str11 = "abcd"; System.out.println("str1 = str11 : "+ (str1 == str11)); //↑------------------------------------------------------over /** * 情景四: * 局部變量str2,str3存儲的是存儲兩個拘留字符串對象(intern字符串對象)的地址。 * * 第三行代碼原理(str2+str3): * 運行期JVM首先會在堆中創建一個StringBuilder類, * 同時用str2指向的拘留字符串對象完成初始化, * 然后調用append方法完成對str3所指向的拘留字符串的合并, * 接著調用StringBuilder的toString()方法在堆中創建一個String對象, * 最后將剛生成的String對象的堆地址存放在局部變量str3中。 * * 而str5存儲的是字符串池中"abcd"所對應的拘留字符串對象的地址。 * str4與str5地址當然不一樣了。 * * 內存中實際上有五個字符串對象: * 三個拘留字符串對象、一個String對象和一個StringBuilder對象。 */ String str2 = "ab"; //1個對象 String str3 = "cd"; //1個對象 String str4 = str2+str3; String str5 = "abcd"; System.out.println("str4 = str5 : " + (str4==str5)); // false //↑------------------------------------------------------over /** * 情景五: * JAVA編譯器對string + 基本類型/常量 是當成常量表達式直接求值來優化的。 * 運行期的兩個string相加,會產生新的對象的,存儲在堆(heap)中 */ String str6 = "b"; String str7 = "a" + str6; String str67 = "ab"; System.out.println("str7 = str67 : "+ (str7 == str67)); //↑str6為變量,在運行期才會被解析。 final String str8 = "b"; String str9 = "a" + str8; String str89 = "ab"; System.out.println("str9 = str89 : "+ (str9 == str89)); //↑str8為常量變量,編譯期會被優化 //↑------------------------------------------------------over?
?
?
5.Java 中的集合
Java集合分為 value 與? key - value (Collection Map)兩種
存儲值得有 list和Set
List是有序的可以重復
Set是無序的不可以重復
存儲Key - value 有Map
6.ArrayList 和LinkList 區別
ArrayList? 底層使用是數組
※? 數組具有索引查詢特定元素較快。而插入刪除較慢。(數組在內存中是一塊連續的內存。如果插入刪除需要移動內存)
LinkList? 底層使用鏈表
※鏈表內存是不需要連續的。在當前元素中存放下一個或上一個元素地址。查詢需要從頭開始找。效率低。
拆入是不需要移動內存。只需要改變引用指向即可。所以插入或者刪除效率高
7.HashMap和HashTable區別。HashMap和ConcurrentHashMap區別
相同點:HashMap和HashTable都可以存儲key? - value的數據
不同點:
1.HashMap是可以將NULL作為key或者Value ,HashTable是不可以的
2.HashMap是線程不安全的,效率較高。而HashTable是線程安全的。效率較低
我想線程安全又想效率高?
ConcurrentHashMap 通過整個Map分為N個segment(類似HashMap)。
可以提供相同的線程安全。但效率提高N倍。默認是16倍。
?8.拷貝一個文件工具類使用字節流還是字符流?
拷貝文件不確定是否包含字符流。有可能有字節。(圖片、聲音、圖形) 考慮通用性使用字節流。
字節流附加:
1.IO流概述 概述:IO流簡單來說就是Input和Output流,IO流主要是用來處理設備之間的數據傳輸,Java對于數據的操作都是通過流實現,而java用于操作流的對象都在IO包中。 分類:按操作數據分為:字節流和字符流。 如:Reader和InpurStream按流向分:輸入流和輸出流。如:InputStream和OutputStream IO流常用的基類:* InputStream , OutputStream 字符流的抽象基類:* Reader , Writer 由上面四個類派生的子類名稱都是以其父類名作為子類的后綴:如:FileReader和FileInputStream
?
1. 字符流簡介: * 字符流中的對象融合了編碼表,也就是系統默認的編碼表。我們的系統一般都是GBK編碼。 * 字符流只用來處理文本數據,字節流用來處理媒體數據。 * 數據最常見的表現方式是文件,字符流用于操作文件的子類一般是FileReader和FileWriter。 2.字符流讀寫: 注意事項: * 寫入文件后必須要用flush()刷新。 * 用完流后記得要關閉流 * 使用流對象要拋出IO異常* 定義文件路徑時,可以用“/”或者“\\”。 * 在創建一個文件時,如果目錄下有同名文件將被覆蓋。 * 在讀取文件時,必須保證該文件已存在,否則出異常?
import java.io.*; import java.util.Scanner; class CopyText { public static void main(String[] args) throws IOException { sop("請輸入要拷貝的文件的路徑:"); Scanner in = new Scanner(System.in); String source = in.next(); sop("請輸入需要拷貝到那個位置的路徑以及生成的文件名:"); String destination = in.next(); in.close(); CopyTextDemo(source,destination); } /*****************文件Copy*********************/ private static void CopyTextDemo(String source,String destination) { try { FileWriter fw = new FileWriter(destination); FileReader fr = new FileReader(source); char [] buf = new char[1024]; //將Denmo中的文件讀取到buf數組中。 int num = 0; while((num = fr.read(buf))!=-1) { //String(char[] value , int offest,int count) 分配一個新的String,包含從offest開始的count個字符 fw.write(new String(buf,0,num)); } fr.close(); fw.close(); } catch (IOException e) { sop(e.toString()); } } /**********************Println************************/ private static void sop(Object obj) { System.out.println(obj); } } 1. 字符流的緩沖區:BufferedReader和BufferedWreiter * 緩沖區的出現時為了提高流的操作效率而出現的. * 需要被提高效率的流作為參數傳遞給緩沖區的構造函數 * 在緩沖區中封裝了一個數組,存入數據后一次取出 BufferedReader示例: 讀取流緩沖區提供了一個一次讀一行的方法readline,方便對文本數據的獲取。 readline()只返回回車符前面的字符,不返回回車符。如果是復制的話,必須加入newLine(),寫入回車符 newLine()是java提供的多平臺換行符寫入方法。 import java.io.*; class BufferedWriterDemo { public static void main(String[] args) throws IOException { //創建一個字符寫入流對象 FileWriter fw = new FileWriter("buf.txt"); //為了提高字符寫入效率,加入了緩沖技術。 //只要將需要被提高效率的流作為參數傳遞給緩沖區的構造函數即可 BufferedWriter bfw = new BufferedWriter(fw); //bfw.write("abc\r\nde"); //bfw.newLine(); 這行代碼等價于bfw.write("\r\n"),相當于一個跨平臺的換行符 //用到緩沖區就必須要刷新 for(int x = 1; x < 5; x++) { bfw.write("abc"); bfw.newLine(); //java提供了一個跨平臺的換行符newLine(); bfw.flush(); } bfw.flush(); //刷新緩沖區 bfw.close(); //關閉緩沖區,但是必須要先刷新 //注意,關閉緩沖區就是在關閉緩沖中的流對象 fw.close(); //關閉輸入流對象 } }字節流:
1、字節流和字符流的基本操作是相同的,但是要想操作媒體流就需要用到字節流。 2、字節流因為操作的是字節,所以可以用來操作媒體文件。(媒體文件也是以字節存儲的) 3、讀寫字節流:InputStream 輸入流(讀)和OutputStream 輸出流(寫) 4、字節流操作可以不用刷新流操作。 5、InputStream特有方法: int available();//返回文件中的字節個數 注:可以利用此方法來指定讀取方式中傳入數組的長度,從而省去循環判斷。但是如果文件較大,而虛擬機啟動分配的默認內存一般為64M。當文件過大時,此數組長度所占內存空間就會溢出。所以,此方法慎用,當文件不大時,可以使用。 import java.io.*; class CopyPic { public static void main(String[] args){ copyBmp(); System.out.println("復制完成"); } public static void copyBmp() { FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream("F:\\java_Demo\\day9_28\\1.bmp"); //寫入流關聯文件 fos = new FileOutputStream("F:\\java_Demo\\day9_28\\2.bmp"); //讀取流關聯文件 byte[] copy = new byte[1024]; int len = 0; while((len=fis.read(copy))!=-1) { fos.write(copy,0,len); } } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("復制文件異常"); } finally { try { if(fis!=null) fis.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("讀取流"); } } } }
?
9.線程實現方式?
1.繼承Thread;類實現一個線程
2.實現Runnable接口實現一個線程
繼承過展性不強。Java只支持單繼承。
3.怎么啟動?
Thread? thread?= new Thread(繼承Thread的對象/實現Runnable對象)
thread.start();
啟動線程使用start方法。而啟動以后執行了run方法。
4.怎么區分線程?
thread.setName("設置一個線程名稱")。
線程:
1:什么是線程?線程是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。程序員可以通過它進行多處理器編程,你可以使用多線程對運算密集型任務提速。比如,如果一個線程完成一個任務要100毫秒,那么用十個線程完成改任務只需10毫秒。Java在語言層面對多線程提供了卓越的支持,它也是一個很好的賣點。欲了解更多詳細信息請點擊這里。 2:線程和進程有什么區別?線程是進程的子集,一個進程可以有很多線程,每條線程并行執行不同的任務。不同的進程使用不同的內存空間,而所有的線程共享一片相同的內存空間。別把它和棧內存搞混,每個線程都擁有單獨的棧內存用來存儲本地數據。更多詳細信息請點擊這里。 3:如何在Java中實現線程?在語言層面有兩種方式。java.lang.Thread 類的實例就是一個線程但是它需要調用java.lang.Runnable接口來執行,由于線程類本身就是調用的Runnable接口所以你可以繼承java.lang.Thread 類或者直接調用Runnable接口來重寫run()方法實現線程。更多詳細信息請點擊這里. 4:用Runnable還是Thread?這個問題是上題的后續,大家都知道我們可以通過繼承Thread類或者調用Runnable接口來實現線程,問題是,那個方法更好呢?什么情況下使用它?這個問題很容易回答,如果你知道Java不支持類的多重繼承,但允許你調用多個接口。所以如果你要繼承其他類,當然是調用Runnable接口好了。更多詳細信息請點擊這里。 5:Thread 類中的start(:和 run(:方法有什么區別?這個問題經常被問到,但還是能從此區分出面試者對Java線程模型的理解程度。start()方法被用來啟動新創建的線程,而且start()內部調用了run()方法,這和直接調用run()方法的效果不一樣。當你調用run()方法的時候,只會是在原來的線程中調用,沒有新的線程啟動,start()方法才會啟動新線程。更多討論請點擊這里 6:Java中Runnable和Callable有什么不同?Runnable和Callable都代表那些要在不同的線程中執行的任務。Runnable從JDK1.0開始就有了,Callable是在JDK1.5增加的。它們的主要區別是Callable的 call(:方法可以返回值和拋出異常,而Runnable的run()方法沒有這些功能。Callable可以返回裝載有計算結果的Future對象。我的博客有更詳細的說明。 7:Java中CyclicBarrier 和 CountDownLatch有什么不同?CyclicBarrier 和 CountDownLatch 都可以用來讓一組線程等待其它線程。與 CyclicBarrier 不同的是,CountdownLatch 不能重新使用。點此查看更多信息和示例代碼。 8:Java內存模型是什么?Java內存模型規定和指引Java程序在不同的內存架構、CPU和操作系統間有確定性地行為。它在多線程的情況下尤其重要。Java內存模型對一個線程所做的變動能被其它線程可見提供了保證,它們之間是先行發生關系。這個關系定義了一些規則讓程序員在并發編程時思路更清晰。比如,先行發生關系確保了:線程內的代碼能夠按先后順序執行,這被稱為程序次序規則。對于同一個鎖,一個解鎖操作一定要發生在時間上后發生的另一個鎖定操作之前,也叫做管程鎖定規則。前一個對volatile的寫操作在后一個volatile的讀操作之前,也叫volatile變量規則。一個線程內的任何操作必需在這個線程的start()調用之后,也叫作線程啟動規則。一個線程的所有操作都會在線程終止之前,線程終止規則。一個對象的終結操作必需在這個對象構造完成之后,也叫對象終結規則。可傳遞性我強烈建議大家閱讀《Java并發編程實踐》第十六章來加深對Java內存模型的理解。 9:Java中的volatile 變量是什么?volatile是一個特殊的修飾符,只有成員變量才能使用它。在Java并發程序缺少同步類的情況下,多線程對成員變量的操作對其它線程是透明的。volatile變量可以保證下一個讀取操作會在前一個寫操作之后發生,就是上一題的volatile變量規則。點擊這里查看更多volatile的相關內容。 10:什么是線程安全?Vector是一個線程安全類嗎? 如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的。一個線程安全的計數器類的同一個實例對象在被多個線程使用的情況下也不會出現計算失誤。很顯然你可以將集合類分成兩組,線程安全和非線程安全的。Vector 是用同步方法來實現線程安全的, 而和它相似的ArrayList不是線程安全的。 11:Java中什么是競態條件?競態條件會導致程序在并發情況下出現一些bugs。多線程對一些資源的競爭的時候就會產生競態條件,如果首先要執行的程序競爭失敗排到后面執行了,那么整個程序就會出現一些不確定的bugs。這種bugs很難發現而且會重復出現,因為線程間的隨機競爭。一個例子就是無序處理,詳見答案。 12:Java中如何停止一個線程?Java提供了很豐富的API但沒有為停止線程提供API。JDK 1.0本來有一些像stop(), suspend(:和 resume()的控制方法但是由于潛在的死鎖威脅因此在后續的JDK版本中他們被棄用了,之后Java API的設計者就沒有提供一個兼容且線程安全的方法來停止一個線程。當run(:或者 call(:方法執行完的時候線程會自動結束,如果要手動結束一個線程,你可以用volatile 布爾變量來退出run()方法的循環或者是取消任務來中斷線程。點擊這里查看示例代碼。 13:一個線程運行時發生異常會怎樣?這是我在一次面試中遇到的一個很刁鉆的Java面試題, 簡單的說,如果異常沒有被捕獲該線程將會停止執行。Thread.UncaughtExceptionHandler是用于處理未捕獲異常造成線程突然中斷情況的一個內嵌接口。當一個未捕獲異常將造成線程中斷的時候JVM會使用Thread.getUncaughtExceptionHandler()來查詢線程的UncaughtExceptionHandler并將線程和異常作為參數傳遞給handler的uncaughtException()方法進行處理。 14:如何在兩個線程間共享數據?你可以通過共享對象來實現這個目的,或者是使用像阻塞隊列這樣并發的數據結構。這篇教程《Java線程間通信》(涉及到在兩個線程間共享對象)用wait和notify方法實現了生產者消費者模型。 15:Java中notify 和 notifyAll有什么區別?這又是一個刁鉆的問題,因為多線程可以等待單監控鎖,Java API 的設計人員提供了一些方法當等待條件改變的時候通知它們,但是這些方法沒有完全實現。notify()方法不能喚醒某個具體的線程,所以只有一個線程在等待的時候它才有用武之地。而notifyAll()喚醒所有線程并允許他們爭奪鎖確保了至少有一個線程能繼續運行。我的博客有更詳細的資料和示例代碼。 16:為什么wait, notify 和 notifyAll這些方法不在thread類里面?這是個設計相關的問題,它考察的是面試者對現有系統和一些普遍存在但看起來不合理的事物的看法。回答這些問題的時候,你要說明為什么把這些方法放在Object類里是有意義的,還有不把它放在Thread類里的原因。一個很明顯的原因是JAVA提供的鎖是對象級的而不是線程級的,每個對象都有鎖,通過線程獲得。如果線程需要等待某些鎖那么調用對象中的wait()方法就有意義了。如果wait()方法定義在Thread類中,線程正在等待的是哪個鎖就不明顯了。簡單的說,由于wait,notify和notifyAll都是鎖級別的操作,所以把他們定義在Object類中因為鎖屬于對象。你也可以查看這篇文章了解更多。 17:什么是ThreadLocal變量?ThreadLocal是Java里一種特殊的變量。每個線程都有一個ThreadLocal就是每個線程都擁有了自己獨立的一個變量,競爭條件被徹底消除了。它是為創建代價高昂的對象獲取線程安全的好方法,比如你可以用ThreadLocal讓SimpleDateFormat變成線程安全的,因為那個類創建代價高昂且每次調用都需要創建不同的實例所以不值得在局部范圍使用它,如果為每個線程提供一個自己獨有的變量拷貝,將大大提高效率。首先,通過復用減少了代價高昂的對象的創建個數。其次,你在沒有使用高代價的同步或者不變性的情況下獲得了線程安全。線程局部變量的另一個不錯的例子是ThreadLocalRandom類,它在多線程環境中減少了創建代價高昂的Random對象的個數。查看答案了解更多。 18:什么是FutureTask?在Java并發程序中FutureTask表示一個可以取消的異步運算。它有啟動和取消運算、查詢運算是否完成和取回運算結果等方法。只有當運算完成的時候結果才能取回,如果運算尚未完成get方法將會阻塞。一個FutureTask對象可以對調用了Callable和Runnable的對象進行包裝,由于FutureTask也是調用了Runnable接口所以它可以提交給Executor來執行。 19:Java中interrupted 和 isInterruptedd方法的區別?interrupted(:和 isInterrupted()的主要區別是前者會將中斷狀態清除而后者不會。Java多線程的中斷機制是用內部標識來實現的,調用Thread.interrupt()來中斷一個線程就會設置中斷標識為true。當中斷線程調用靜態方法Thread.interrupted()來檢查中斷狀態時,中斷狀態會被清零。而非靜態方法isInterrupted()用來查詢其它線程的中斷狀態且不會改變中斷狀態標識。簡單的說就是任何拋出InterruptedException異常的方法都會將中斷狀態清零。無論如何,一個線程的中斷狀態有有可能被其它線程調用中斷來改變。 20:為什么wait和notify方法要在同步塊中調用?主要是因為Java API強制要求這樣做,如果你不這么做,你的代碼會拋出IllegalMonitorStateException異常。還有一個原因是為了避免wait和notify之間產生競態條件。 21:為什么你應該在循環中檢查等待條件?處于等待狀態的線程可能會收到錯誤警報和偽喚醒,如果不在循環中檢查等待條件,程序就會在沒有滿足結束條件的情況下退出。因此,當一個等待線程醒來時,不能認為它原來的等待狀態仍然是有效的,在notify()方法調用之后和等待線程醒來之前這段時間它可能會改變。這就是在循環中使用wait()方法效果更好的原因,你可以在Eclipse中創建模板調用wait和notify試一試。如果你想了解更多關于這個問題的內容,我推薦你閱讀《Effective Java》這本書中的線程和同步章節。 22:Java中的同步集合與并發集合有什么區別?同步集合與并發集合都為多線程和并發提供了合適的線程安全的集合,不過并發集合的可擴展性更高。在Java1.5之前程序員們只有同步集合來用且在多線程并發的時候會導致爭用,阻礙了系統的擴展性。Java5介紹了并發集合像ConcurrentHashMap,不僅提供線程安全還用鎖分離和內部分區等現代技術提高了可擴展性。更多內容詳見答案。 23:Java中堆和棧有什么不同?為什么把這個問題歸類在多線程和并發面試題里?因為棧是一塊和線程緊密相關的內存區域。每個線程都有自己的棧內存,用于存儲本地變量,方法參數和棧調用,一個線程中存儲的變量對其它線程是不可見的。而堆是所有線程共享的一片公用內存區域。對象都在堆里創建,為了提升效率線程會從堆中弄一個緩存到自己的棧,如果多個線程使用該變量就可能引發問題,這時volatile 變量就可以發揮作用了,它要求線程從主存中讀取變量的值。 24:什么是線程池? 為什么要使用它?創建線程要花費昂貴的資源和時間,如果任務來了才創建線程那么響應時間會變長,而且一個進程能創建的線程數有限。為了避免這些問題,在程序啟動的時候就創建若干線程來響應處理,它們被稱為線程池,里面的線程叫工作線程。從JDK1.5開始,Java API提供了Executor框架讓你可以創建不同的線程池。比如單線程池,每次處理一個任務;數目固定的線程池或者是緩存線程池(一個適合很多生存期短的任務的程序的可擴展線程池)。更多內容詳見這篇文章。 25:如何寫代碼來解決生產者消費者問題?在現實中你解決的許多線程問題都屬于生產者消費者模型,就是一個線程生產任務供其它線程進行消費,你必須知道怎么進行線程間通信來解決這個問題。比較低級的辦法是用wait和notify來解決這個問題,比較贊的辦法是用Semaphore 或者 BlockingQueue來實現生產者消費者模型,這篇教程有實現它。 26:如何避免死鎖?Java多線程中的死鎖死鎖是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。這是一個嚴重的問題,因為死鎖會讓你的程序掛起無法完成任務,死鎖的發生必須滿足以下四個條件:互斥條件:一個資源每次只能被一個進程使用。請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。不剝奪條件:進程已獲得的資源,在末使用完之前,不能強行剝奪。循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關系。避免死鎖最簡單的方法就是阻止循環等待條件,將系統中所有的資源設置標志位、排序,規定所有的進程申請資源必須以一定的順序(升序或降序)做操作來避免死鎖。這篇教程有代碼示例和避免死鎖的討論細節。 27:Java中活鎖和死鎖有什么區別?這是上題的擴展,活鎖和死鎖類似,不同之處在于處于活鎖的線程或進程的狀態是不斷改變的,活鎖可以認為是一種特殊的饑餓。一個現實的活鎖例子是兩個人在狹小的走廊碰到,兩個人都試著避讓對方好讓彼此通過,但是因為避讓的方向都一樣導致最后誰都不能通過走廊。簡單的說就是,活鎖和死鎖的主要區別是前者進程的狀態可以改變但是卻不能繼續執行。 28:怎么檢測一個線程是否擁有鎖?我一直不知道我們竟然可以檢測一個線程是否擁有鎖,直到我參加了一次電話面試。在java.lang.Thread中有一個方法叫holdsLock(),它返回true如果當且僅當當前線程擁有某個具體對象的鎖。你可以查看這篇文章了解更多。 29:你如何在Java中獲取線程堆棧?對于不同的操作系統,有多種方法來獲得Java進程的線程堆棧。當你獲取線程堆棧時,JVM會把所有線程的狀態存到日志文件或者輸出到控制臺。在Windows你可以使用Ctrl + Break組合鍵來獲取線程堆棧,Linux下用kill -3命令。你也可以用jstack這個工具來獲取,它對線程id進行操作,你可以用jps這個工具找到id。 30:JVM中哪個參數是用來控制線程的棧堆棧小的這個問題很簡單, -Xss參數用來控制線程的堆棧大小。你可以查看JVM配置列表來了解這個參數的更多信息。 31:Java中synchronized 和 ReentrantLock 有什么不同?Java在過去很長一段時間只能通過synchronized關鍵字來實現互斥,它有一些缺點。比如你不能擴展鎖之外的方法或者塊邊界,嘗試獲取鎖時不能中途取消等。Java 5 通過Lock接口提供了更復雜的控制來解決這些問題。 ReentrantLock 類實現了 Lock,它擁有與 synchronized 相同的并發性和內存語義且它還具有可擴展性。你可以查看這篇文章了解更多 32:有三個線程T1,T2,T3,怎么確保它們按順序執行?在多線程中有多種方法讓線程按特定順序執行,你可以用線程類的join()方法在一個線程中啟動另一個線程,另外一個線程完成該線程繼續執行。為了確保三個線程的順序你應該先啟動最后一個(T3調用T2,T2調用T1),這樣T1就會先完成而T3最后完成。你可以查看這篇文章了解更多。 33:Thread類中的yield方法有什么作用?Yield方法可以暫停當前正在執行的線程對象,讓其它有相同優先級的線程執行。它是一個靜態方法而且只保證當前線程放棄CPU占用而不能保證使其它線程一定能占用CPU,執行yield()的線程有可能在進入到暫停狀態后馬上又被執行。點擊這里查看更多yield方法的相關內容。 34:Java中ConcurrentHashMap的并發度是什么?ConcurrentHashMap把實際map劃分成若干部分來實現它的可擴展性和線程安全。這種劃分是使用并發度獲得的,它是ConcurrentHashMap類構造函數的一個可選參數,默認值為16,這樣在多線程情況下就能避免爭用。欲了解更多并發度和內部大小調整請閱讀我的文章How ConcurrentHashMap works in Java。 35:Java中Semaphore是什么?Java中的Semaphore是一種新的同步類,它是一個計數信號。從概念上講,從概念上講,信號量維護了一個許可集合。如有必要,在許可可用前會阻塞每一個 acquire(),然后再獲取該許可。每個 release()添加一個許可,從而可能釋放一個正在阻塞的獲取者。但是,不使用實際的許可對象,Semaphore只對可用許可的號碼進行計數,并采取相應的行動。信號量常常用于多線程的代碼中,比如數據庫連接池。更多詳細信息請點擊這里。 36:如果你提交任務時,線程池隊列已滿。會時發會生什么?這個問題問得很狡猾,許多程序員會認為該任務會阻塞直到線程池隊列有空位。事實上如果一個任務不能被調度執行那么ThreadPoolExecutor’s submit()方法將會拋出一個RejectedExecutionException異常。 37:Java線程池中submit(:和 execute()方法有什么區別?兩個方法都可以向線程池提交任務,execute()方法的返回類型是void,它定義在Executor接口中, 而submit()方法可以返回持有計算結果的Future對象,它定義在ExecutorService接口中,它擴展了Executor接口,其它線程池類像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有這些方法。更多詳細信息請點擊這里。 38:什么是阻塞式方法?阻塞式方法是指程序會一直等待該方法完成期間不做其他事情,ServerSocket的accept()方法就是一直等待客戶端連接。這里的阻塞是指調用結果返回之前,當前線程會被掛起,直到得到結果之后才會返回。此外,還有異步和非阻塞式方法在任務完成前就返回。更多詳細信息請點擊這里。 39:Swing是線程安全的嗎? 為什么?你可以很肯定的給出回答,Swing不是線程安全的,但是你應該解釋這么回答的原因即便面試官沒有問你為什么。當我們說swing不是線程安全的常常提到它的組件,這些組件不能在多線程中進行修改,所有對GUI組件的更新都要在AWT線程中完成,而Swing提供了同步和異步兩種回調方法來進行更新。點擊這里查看更多swing和線程安全的相關內容。 41:Java中invokeAndWait 和 invokeLater有什么區別?這兩個方法是Swing API 提供給Java開發者用來從當前線程而不是事件派發線程更新GUI組件用的。InvokeAndWait()同步更新GUI組件,比如一個進度條,一旦進度更新了,進度條也要做出相應改變。如果進度被多個線程跟蹤,那么就調用invokeAndWait()方法請求事件派發線程對組件進行相應更新。而invokeLater()方法是異步調用更新組件的。更多詳細信息請點擊這里。 42:Swing API中那些方法是線程安全的?這個問題又提到了swing和線程安全,雖然組件不是線程安全的但是有一些方法是可以被多線程安全調用的,比如repaint(), revalidate()。 JTextComponent的setText()方法和JTextArea的insert(:和 append(:方法也是線程安全的。 43:如何在Java中創建Immutable對象?這個問題看起來和多線程沒什么關系, 但不變性有助于簡化已經很復雜的并發程序。Immutable對象可以在沒有同步的情況下共享,降低了對該對象進行并發訪問時的同步化開銷。可是Java沒有@Immutable這個注解符,要創建不可變類,要實現下面幾個步驟:通過構造方法初始化所有成員、對變量不要提供setter方法、將所有的成員聲明為私有的,這樣就不允許直接訪問這些成員、在getter方法中,不要直接返回對象本身,而是克隆對象,并返回對象的拷貝。我的文章how to make an object Immutable in Java有詳細的教程,看完你可以充滿自信。 44:Java中的ReadWriteLock是什么?一般而言,讀寫鎖是用來提升并發程序性能的鎖分離技術的成果。Java中的ReadWriteLock是Java 5 中新增的一個接口,一個ReadWriteLock維護一對關聯的鎖,一個用于只讀操作一個用于寫。在沒有寫線程的情況下一個讀鎖可能會同時被多個讀線程持有。寫鎖是獨占的,你可以使用JDK中的ReentrantReadWriteLock來實現這個規則,它最多支持65535個寫鎖和65535個讀鎖。 45:多線程中的忙循環是什么?忙循環就是程序員用循環讓一個線程等待,不像傳統方法wait(), sleep(:或 yield(:它們都放棄了CPU控制,而忙循環不會放棄CPU,它就是在運行一個空循環。這么做的目的是為了保留CPU緩存,在多核系統中,一個等待線程醒來的時候可能會在另一個內核運行,這樣會重建緩存。為了避免重建緩存和減少等待重建的時間就可以使用它了。你可以查看這篇文章獲得更多信息。 46)volatile 變量和 atomic 變量有什么不同?這是個有趣的問題。首先,volatile 變量和 atomic 變量看起來很像,但功能卻不一樣。Volatile變量可以確保先行關系,即寫操作會發生在后續的讀操作之前, 但它并不能保證原子性。例如用volatile修飾count變量那么 count++ 操作就不是原子性的。而AtomicInteger類提供的atomic方法可以讓這種操作具有原子性如getAndIncrement()方法會原子性的進行增量操作把當前值加一,其它數據類型和引用變量也可以進行相似操作。 47:如果同步塊內的線程拋出異常會發生什么?這個問題坑了很多Java程序員,若你能想到鎖是否釋放這條線索來回答還有點希望答對。無論你的同步塊是正常還是異常退出的,里面的線程都會釋放鎖,所以對比鎖接口我更喜歡同步塊,因為它不用我花費精力去釋放鎖,該功能可以在finally block里釋放鎖實現。 48:單例模式的雙檢鎖是什么?這個問題在Java面試中經常被問到,但是面試官對回答此問題的滿意度僅為50%。一半的人寫不出雙檢鎖還有一半的人說不出它的隱患和Java1.5是如何對它修正的。它其實是一個用來創建線程安全的單例的老方法,當單例實例第一次被創建時它試圖用單個鎖進行性能優化,但是由于太過于復雜在JDK1.4中它是失敗的,我個人也不喜歡它。無論如何,即便你也不喜歡它但是還是要了解一下,因為它經常被問到。你可以查看how double checked locking on Singleton works這篇文章獲得更多信息。 49:如何在Java中創建線程安全的Singleton?這是上面那個問題的后續,如果你不喜歡雙檢鎖而面試官問了創建Singleton類的替代方法,你可以利用JVM的類加載和靜態變量初始化特征來創建Singleton實例,或者是利用枚舉類型來創建Singleton,我很喜歡用這種方法。你可以查看這篇文章獲得更多信息。 50:如何強制啟動一個線程?這個問題就像是如何強制進行Java垃圾回收,目前還沒有覺得方法,雖然你可以使用System.gc()來進行垃圾回收,但是不保證能成功。在Java里面沒有辦法強制啟動一個線程,它是被線程調度器控制著且Java沒有公布相關的API。 51:Java中的fork join框架是什么?fork join框架是JDK7中出現的一款高效的工具,Java開發人員可以通過它充分利用現代服務器上的多處理器。它是專門為了那些可以遞歸劃分成許多子模塊設計的,目的是將所有可用的處理能力用來提升程序的性能。fork join框架一個巨大的優勢是它使用了工作竊取算法,可以完成更多任務的工作線程可以從其它線程中竊取任務來執行。你可以查看這篇文章獲得更多信息。 52:Java多線程中調用wait(:和 sleep()方法有什么不同?Java程序中wait 和 sleep都會造成某種形式的暫停,它們可以滿足不同的需要。wait()方法用于線程間通信,如果等待條件為真且其它線程被喚醒時它會釋放鎖,而sleep()方法僅僅釋放CPU資源或者讓當前線程停止執行一段時間,但不會釋放鎖。?
10.使用線程并發庫?
java.util.current包對于線程優化。管理各項操作。使線程變得得心應手。包括線程的運行、線程池的創建、線程生命周期的控制
?Java通過Executors四種靜態方法創建四種線程池
| newCachedThreadPool() ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? | -緩存型池子,先查看池中有沒有以前建立的線程,如果有,就 reuse.如果沒有,就建一個新的線程加入池中 -緩存型池子通常用于執行一些生存期很短的異步型任務 因此在一些面向連接的daemon型SERVER中用得不多。但對于生存期短的異步任務,它是Executor的首選。 -能reuse的線程,必須是timeout IDLE內的池中線程,缺省 ? ? timeout是60s,超過這個IDLE時長,線程實例將被終止及移出池。 ?注意,放入CachedThreadPool的線程不必擔心其結束,超過TIMEOUT不活動,其會自動被終止。? ? ? |
| newFixedThreadPool(int) | -newFixedThreadPool與cacheThreadPool差不多,也是能reuse就用,但不能隨時建新的線程 -其獨特之處:任意時間點,最多只能有固定數目的活動線程存在,此時如果有新的線程要建立,只能放在另外的隊列中等待,直到當前的線程中某個線程終止直接被移出池子 -和cacheThreadPool不同,FixedThreadPool沒有IDLE機制(可能也有,但既然文檔沒提,肯定非常長,類似依賴上層的TCP或UDP IDLE機制之類的),所以FixedThreadPool多數針對一些很穩定很固定的正規并發線程,多用于服務器 -從方法的源代碼看,cache池和fixed 池調用的是同一個底層 池,只不過參數不同: fixed池線程數固定,并且是0秒IDLE(無IDLE) ? ? cache池線程數支持0-Integer.MAX_VALUE(顯然完全沒考慮主機的資源承受能力),60秒IDLE?? ? ? |
| newScheduledThreadPool(int) | -調度型線程池 -這個池子里的線程可以按schedule依次delay執行,或周期執行 |
| SingleThreadExecutor() | -單例線程,任意時間池中只能有一個線程 -用的是和cache池和fixed池相同的底層池,但線程數目是1-1,0秒IDLE(無IDLE) |
10.1線程池的作用?
1.限制線程的個數,不會導致由于線程過多導致系統運行緩慢或崩潰
2.線程池不需要每次都去創建或銷毀。節約了資源
3.線程池不需要每次都去創建。響應時間更快。
11.常用的設計模式有哪些?
設計模式就是應該前任無數次實踐總結出的。設計過程中可以反復使用的。可以解決待定問題的設計方法
單例模式(飽漢模式,饑漢模式)
1.構造方法私有化。讓出自己類創建其他地方都不能創建
2.在自己類中創建一個單實例(飽漢模式是一出來就創建單例,而饑漢模式需要時候才創建)
3.提供一個方法獲取實例對象
飽漢模式 package Jzen.Util;public class PersionFactory {private PersionFactory(){}private static PersionFactory instance = new PersionFactory();public static PersionFactory getInstance(){return instance;}} 饑漢模式 package Jzen.Util;public class PersionFactory {private PersionFactory(){}private static PersionFactory instance = null;public synchronized static PersionFactory getInstance(){if(instance == null){instance = new PersionFactory();}return instance;}}工廠模式? Spring ioc使用工廠模式
對象創建交給一個工廠去創建。
代理模式? Spring aop就是使用的動態代理
12.http get和Post請求區別?
1.get與post不同的請求對yrl不同的操作。GET一般用于獲取查詢信息,而POST一般用于更新資源信息
2.GET 請求提交參數會在地址欄顯示而POST不會再地址欄顯示出來。
3.傳輸數據大小
4.安全性。POST的安全性比GET 高
13.Servlet 的理解。或者Servlet是什么?
主要用于交互式游覽和修改數據。是Java服務端的程序。
HTTPServlet重寫doGet或者DoPost重寫來處理。
14.Servlet生命周期?
Servlet有良好的生命周期。包括加載與實例化、初始化、處理請求、服務結束。
這個生命周期有init、services和destroy方法表達。
1. init()方法
? ? ? 在Servlet的生命周期中,僅執行一次init()方法,它是在服務器裝入Servlet時執行的,可以配置服務器,以在啟動服務器或客戶機首次訪問Servlet時裝入Servlet。無論有多少客戶機訪問Servlet,都不會重復執行init();
2. service()方法
? ? ? 它是Servlet的核心,每當一個客戶請求一個HttpServlet對象,該對象的Service()方法就要調用,而且傳遞給這個方法一個“請求”(ServletRequest)對象和一個“響應”(ServletResponse)對象作為參數。在HttpServlet中已存在Service()方法。默認的服務功能是調用與HTTP請求的方法相應的do功能。
3. destroy()方法
? ? ? 僅執行一次,在服務器端停止且卸載Servlet時執行該方法,有點類似于C++的delete方法。一個Servlet在運行service()方法時可能會產生其他的線程,因此需要確認在調用destroy()方法時,這些線程已經終止或完成。
? ? ?下面來談談Servlet的生命周期,Servlet的生命周期是由Servlet容器來控制的,它始于裝入Web服務器的內存時,并在終止或重新裝入Servlet時結束。這項操作一般是動態執行的。然而,Server通常會提供一個管理的選項,用于在Server啟動時強制裝載和初始化特定的Servlet。
15.Servlet 中Forword() 與Redirect()區別?
1.從地址欄顯示來說?
forward是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL的響應內容讀取過來,然后把這些內容再發給瀏覽器.瀏覽器根本不知道服務器發送的內容從哪里來的,所以它的地址欄還是原來的地址.
redirect是服務端根據邏輯,發送一個狀態碼,告訴瀏覽器重新去請求那個地址.所以地址欄顯示的是新的URL.
2.從數據共享來說?
forward:轉發頁面和轉發到的頁面可以共享request里面的數據.
redirect:不能共享數據.
3.從運用地方來說?
forward:一般用于用戶登陸的時候,根據角色轉發到相應的模塊.
redirect:一般用于用戶注銷登陸時返回主頁面和跳轉到其它的網站等.
4.從效率來說?
forward:高.
redirect:低.
轉發是服務器行為,重定向是客戶端行為
轉發過程:客戶瀏覽器發送http請求----》web服務器接受此請求--》調用內部的一個方法在容器內部完成請求處理和轉發動作----》將目標資源 發送給客戶;在這里,轉發的路徑必須是同一個web容器下的url,其不能轉向到其他的web路徑上去,中間傳遞的是自己的容器內的request。在客 戶瀏覽器路徑欄顯示的仍然是其第一次訪問的路徑,也就是說客戶是感覺不到服務器做了轉發的。轉發行為是瀏覽器只做了一次訪問請求。?
重定向過程:客戶瀏覽器發送http請求----》web服務器接受后發送302狀態碼響應及對應新的location給客戶瀏覽器--》客戶瀏覽器發現 是302響應,則自動再發送一個新的http請求,請求url是新的location地址----》服務器根據此請求尋找資源并發送給客戶。在這里 location可以重定向到任意URL,既然是瀏覽器重新發出了請求,則就沒有什么request傳遞的概念了。在客戶瀏覽器路徑欄顯示的是其重定向的 路徑,客戶可以觀察到地址的變化的。重定向行為是瀏覽器做了至少兩次的訪問請求的。?
?
15.1 直接轉發和間接轉發的原理及區別是什么?
答:Forward和Redirect代表了兩種請求轉發方式:直接轉發和間接轉發。對應到代碼里,分別是RequestDispatcher類的forward()方法和HttpServletRequest類的sendRedirect()方法。
對于間接方式,服務器端在響應第一次請求的時候,讓瀏覽器再向另外一個URL發出請求,從而達到轉發的目的。它本質上是兩次HTTP請求,對應兩個request對象。
對于直接方式,客戶端瀏覽器只發出一次請求,Servlet把請求轉發給Servlet、HTML、JSP或其它信息資源,由第2個信息資源響應該請求,兩個信息資源共享同一個request對象。
?
16.Jsp和Servlet 相同點和不同點。
Jsp是Servlet的擴展。jsp文件都會繼承HTTPServlet服務(tomcat進行)。也就是jsp最終也是一個Servlet.
這個Servlet對外提供服務。這就是相同點
Servlet要實現html部分必須使用writer輸出html比較麻煩。
Servlet的應用邏輯是在Java中。并且完全從變現層中分離出來。
Jsp是Java+Html組合一個擴展名為jsp文件。JSP側重于視圖。Servlet側重控制邏輯
?
17.Jsp內置對象作用以及用法?
out對象:用來傳送回應的輸出。
request對象:封裝了來自客戶端、瀏覽器的請求信息。
response對象:封裝了服務器的響應信息。
exception對象:封裝了jsp程序執行過程中發生的異常和錯誤信息。
config對象:封裝了應用程序的配置信息。
page對象:指向了當前jsp程序本身。
session對象:與請求有關的會話期
application對象:正在執行的內容
pageContext對象:頁面屬性管理
四大作用域
1.PageContext
2.request
3.session
4.application
可以通過jstl從自大作用域取值。jsp傳遞值。request、session、application、cookie也能傳值。
?
18.Session? Cookie 區別。使用點?
Session? 和 Cookie都是會話跟蹤技術。
Cookie通過客戶端記錄信息確認用戶身份。
Session通過服務端記錄信息確認用戶身份。
但是Session實現依賴于Cookie。SessionId(Session唯一標識存放在客戶端)
Session? Cookie?區別
1.Cookie 數據存放在客戶端。Session數據存放在服務端。
2.Cookie很不安全。別人可以解析存放在本地的Cookie并進行Cookie欺騙考慮到安全應當使用Session
3.Session一定時間內保存服務器上。訪問增多。會占用服務器性能。考慮性能則使用Cookie
4.單個cookie保存數據不能超過4k。很多游覽器控制一個站點最多保存20個cookie
購物車最好使用Cookie。但是Cookie游覽器是可以禁用的。這時候我們要使用cookie+數據庫的形式。
當從Cookie取不出數據。則從數據庫獲取。
?
數據庫
1.數據庫分類及常用數據庫
? 數據庫分為關系型數據庫與非關系性數據庫
關系型:mysql oracle SqlServer等。
菲關系型:Redis? mogodb hadoop等。
2.關系型數據庫與非關系性數據庫區別
非關系型數據庫的優勢:
1. 性能
NOSQL是基于鍵值對的,可以想象成表中的主鍵和值的對應關系,而且不需要經過SQL層的解析,所以性能非常高。
2. 可擴展性
同樣也是因為基于鍵值對,數據之間沒有耦合性,所以非常容易水平擴展。
關系型數據庫的優勢:
1. 復雜查詢
可以用SQL語句方便的在一個表以及多個表之間做非常復雜的數據查詢。
2. 事務支持
使得對于安全性能很高的數據訪問要求得以實現
Mysql? limit m,n分頁語句:
select * from dept order by deptno desc limit 3,3; select * from dept order by deptno desc limit m,n;Oracle 分頁
select * from (select a1.*,rownum rn from (select * from student) a1 where rownum <=5) where rn>=2;
select a1.* from (select student.*,rownum rn from student where rownum <=5) a1 where rn >=3;
select a1.* from (select student.*,rownum rn from student) a1 where rn between 3 and 5;
6.存儲過程的優點
1.存儲過程值在創建時進行編譯。以后每次執行存儲過程都不需要重新編譯。而一般SQL語言每執行一次
就編譯一次。因此使用存儲過程可以大大提高數據庫執行速度。
2.復雜的業務邏輯需要多天SQL語句。會產生大量網絡傳輸。如果使用存儲過程會大大減少。
3.存儲過程可以重復使用。減少開發工作量
4.安全性高。存儲過程屏蔽底層數據庫對象的直接訪問。
7.通過JDBC調用存儲過程?
package xzg;import java.sql.CallableStatement; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types;public class JDBCtest {public static void main(String[] args) {//test();//test2(); test3();}/** 命令行創建的存儲過程函數為: create procedure all_user() select * from user;* 創建一個查詢所有內容的存儲過程* 調用無參存儲過程*/static void test() {Connection conn = Dbutil.open();try {//存儲過程函數固定格式:{call xxx}CallableStatement cs = conn.prepareCall("{call all_user()}");ResultSet rs = cs.executeQuery();while (rs.next()) {int id = rs.getInt(1);String name = rs.getString(2);int age = rs.getInt(3);System.out.println(id + "," + name + "," + age);}} catch (SQLException e) {e.printStackTrace();} finally {Dbutil.close(conn);}}/** 命令行創建的存儲過程函數為:* create procedure insert_user(in myname varchar(20),* in myage tinyint(20)) insert user(username,age) values(myname,myemail); * 表示創建一個插入myname,數據類型為varchar(20); myage,數據類型為tinyint(20)的存儲過程* 調用輸入帶參存儲過程*/static void test2() {Connection conn = Dbutil.open();try {CallableStatement cs = conn.prepareCall("{call insert_user(?,?)}");cs.setString(1, "jack");cs.setInt(2, 10);cs.executeUpdate();} catch (SQLException e) {e.printStackTrace();} finally {Dbutil.close(conn);}}/** 命令行創建的存儲過程函數為:* create procedure getnamebyid(in cid int,* out return_name varchar(20)) select username into return_name* from user where id =cid;* 表示創建一個如果id為cid,那么就輸出返回一個return_name* 調用輸入、輸出帶參存儲過程*/static void test3() {Connection conn = Dbutil.open();try {CallableStatement cs = conn.prepareCall("{call getnamebyid(?,?)}");cs.setInt(1, 3); //索引1,第3個id//輸出參數的話要注冊cs.registerOutParameter(2, Types.CHAR);//注冊后要更新 cs.execute();String name =cs.getString(2); //這個是索引的意思 cs.executeQuery();System.out.println(name);} catch (SQLException e) {e.printStackTrace();} finally {Dbutil.close(conn);}} }8.對于JDBC的理解
Java databases connection? Java數據庫連接。數據庫關系系統是很多。每個數據庫管理系統支持測令是不一樣的。
Java之定義接口讓數據庫廠商自己實現接口,只需要導入廠商開發的實現就可。
9.寫一個訪問JDBC的程序?
加載驅動、獲取參數、設置參數、執行、釋放連接。
10.JDBC中的PreparedStatement相比Statement的好處
?
?
?11.數據庫連接池作用
1.限定數據庫的個數。不會導致由于數據庫連接過多導致程序緩慢或者崩潰、
2. 數據庫連接不需要每次都去創建或銷毀,節約資源。
3.數據庫連接不需要每次都去創建。響應更快。
?
前段部分
1.HTML css JavaScript 在網頁開發的定位?
2.簡單介紹一下Ajax
什么是Ajax? AJax就是異步的JavaScript和xml。可以不用刷新頁面就可以完成數據交互
? ? 作用是什么? 通過Ajax與服務器進行數據交換。AJax實現頁面局部更新。也就是說可以在不重新加載
頁面情況下。對網頁部分進行更新。
怎么來實現?XmlHttpRequest對象。使用這個對象可以異步向服務器發送請求。獲取響應完成拒不更新。
3.JS與JQuery區別?
Jquery是js 的一個框架。封裝js的屬性和方法。增強js的功能。開發更加方便。
? ? ? ?js需要處理一些兼容問題。Jquery進行封裝就可以不用處理兼容問題、
元素js的dom和事件綁定操作麻煩。Jquery封裝后操作方便。
?
框架部分 1.什么是框架? 框架(framework) 是一個框子? 指其約束性,也是一個架子指其支撐性。 2.什么是MVC模式?MVC是Model View Controller 是模型 視圖 控制器的縮寫。 最經典的的就是jsp + Servlet + JavaBean 3.什么是MVC框架? 未了解決傳統的MVC模式的問題而出現的框架。 什么是傳統MVC模式的問題? 1.所有Servlet 和Servlet映射配置都要在web.xml? 項目太大。web.xml就更加龐大。并且不能實現模塊化管理 2.Servlet主要功能就是接受參數,調用邏輯,跳轉頁面。 3.接受參數比較麻煩。需要不斷的request.getParameter.而且不能通過model接收。只能單個接收,接受完后轉換封裝model/ 4.跳轉頁面方式比較單一(forward? redirect)。并且當我頁面名稱改變是需要修改Servlet源碼 ? 現在比較常用的MVC框架: Struts2 Hibernate Spring SpringMVC 4.Struts2 執行流程? .
在Struts2框架中的處理大概分為以下的步驟?
1 用戶發送請求;
2 這個請求經過一系列的過濾器(Filter)(這些過濾器中有一個叫做ActionContextCleanUp的可選過濾器,這個過濾器對于Struts2和其他框架的集成很有幫助,例如:SiteMesh Plugin)
3 接著FilterDispatcher被調用,FilterDispatcher詢問ActionMapper來決定這個請求是否需要調用某個Action ;
4 ?如果需要處理,ActionMapper會通知FilterDispatcher,需要處理這個請求,FilterDispatcher會停止過濾器鏈以后的部分,(這也就是為什么,FilterDispatcher應該出現在過濾器鏈的最后的原因)。FilterDispatcher把請求的處理交給ActionProxy ;
5 ActionProxy通過Configuration Manager詢問框架的配置文件struts.xml,找到需要調用的Action類 。(在服務器啟動的時候,ConfigurationManager就會把struts.xml中的所有信息讀到內存里,并緩存,當ActionProxy帶著URL向他詢問要運行哪個Action的時候,就可以直接匹配、查找并回答了)
6 ActionProxy創建一個ActionInvocation的實例。?
7 ActionInvocation實例使用命名模式來調用,在調用Action的過程前后,涉及到一系列相關攔截器(Intercepter)的調用。?
8 一旦Action執行完畢,ActionInvocation負責根據struts.xml中的配置找到對應的返回結果。返回結果通常是(但不總是,也可 能是另外的一個Action鏈)一個需要被表示的JSP或者FreeMarker的模版。在表示的過程中可以使用Struts2 框架中繼承的標簽。
?9?最后,ActionInvocation對象倒序執行攔截器。
10.ActionInvocation對象執行完畢后,響應用戶。
?
注意:2.1.3之后的核心過濾器由FilterDispatcher換成StrutsPrepareAndExecuteFilter。
?
談談攔截器與過濾器的區別:
1、攔截器是基于java反射機制的,而過濾器是基于函數回調的。
2、過濾器依賴于servlet容器,而攔截器不依賴于servlet容器。
3、攔截器只能對Action請求起作用,而過濾器則可以對幾乎所有請求起作用。
4、攔截器可以訪問Action上下文、值棧里的對象,而過濾器不能。
5、在Action的生命周期中,攔截器可以多次調用,而過濾器只能在容器初始化時被調用一次。
?
SpringMVC流程
1、? 用戶發送請求至前端控制器DispatcherServlet。
2、? DispatcherServlet收到請求調用HandlerMapping處理器映射器。
3、? 處理器映射器找到具體的處理器(可以根據xml配置、注解進行查找),生成處理器對象及處理器攔截器(如果有則生成)一并返回給DispatcherServlet。
4、? DispatcherServlet調用HandlerAdapter處理器適配器。
5、? HandlerAdapter經過適配調用具體的處理器(Controller,也叫后端控制器)。
6、? Controller執行完成返回ModelAndView。
7、? HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet。
8、? DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器。
9、? ViewReslover解析后返回具體View。
10、DispatcherServlet根據View進行渲染視圖(即將模型數據填充至視圖中)。
11、 DispatcherServlet響應用戶。
7.struts2 和SpringMVC有什么不同? 1.核心控制器不同:SpringMVC核心控制器是Servlet,Struts2是Filter。 2.控制器實例:SpringMVC是基于方法設計。而Struts2是基于對象,每次發一次請求都會實例一個action,每個都會被注入屬性,而Spring更像Servlet一樣。 而SpringMVc更像Servlet只有一個實例,每次請求執行對應的方法即可(由于是單列實例,所以硬蛋避免全局變量的修改,這樣會產生線程安全問題) 3.管理方式大多數使用SPring ,Spring可能對SpringMVc控制更加簡單方便。 4.參數傳遞:ValueStack 和SpringMVC通過方法進行接收 。ValueStack 過于龐大。 6.SpringMVC 對Ajax可以直接返回數據。通過RequestBody 進行對數據JSon轉換。 8.Spring 兩大核心? Spring 是一個輕量級IOC和AOP的容器框架。主要針對JavaBean的生命周期進行管理的輕量級容器。也可以單獨使用。 主要是: IOC: IoC的一個重點是在系統運行中,動態的向某個對象提供它所需要的其他對象。這一點是通過DI(Dependency Injection,依賴注入)來實現的 AOP: 這種在運行時,動態地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程。 10.spring的事務有幾種方式?談談spring事務的隔離級別和傳播行為。聲明事務和編程事務
隔離級別:
- DEFAULT使用數據庫默認的隔離級別
- READ_UNCOMMITTED會出現臟讀,不可重復讀和幻影讀問題
- READ_COMMITTED會出現重復讀和幻影讀
- REPEATABLE_READ會出現幻影讀
- SERIALIZABLE最安全,但是代價最大,性能影響極其嚴重
和傳播行:
- REQUIRED存在事務就融入該事務,不存在就創建事務
- SUPPORTS存在事務就融入事務,不存在則不創建事務
- MANDATORY存在事務則融入該事務,不存在,拋異常
- REQUIRES_NEW總是創建新事務
- NOT_SUPPORTED存在事務則掛起,一直執行非事務操作
- NEVER總是執行非事務,如果當前存在事務則拋異常
- NESTED嵌入式事務
高級部分 1.做過什么數據庫優化? 1.定位查找慢查詢并優化 2.建立索引 創建合適的索引。我們就可以在索引中查詢到記錄。 3.分表 當一張表數據比較多或者某些字段值比較多,并且很少使用采用水平或者垂直分表進行優化 4.讀寫分離 當一臺服務器不能滿足,采用讀寫分離的形式進行分離 5.緩存redis 使用redis來進行緩存 2.如何定位慢查詢? 在項目自驗或啟動時。在啟動Mysql時開啟慢查詢,并且把執行慢的數據記錄到日志。通過查看日志找到對應的慢查詢語句。 參數詳情: slow_query_log 慢查詢開啟狀態slow_query_log_file 慢查詢日志存放的位置(這個目錄需要MySQL的運行帳號的可寫權限,一般設置為MySQL的數據存放目錄)
long_query_time 查詢超過多少秒才記錄
查看慢查詢相關參數
mysql> show variables like 'slow_query%'; +---------------------------+----------------------------------+ | Variable_name | Value | +---------------------------+----------------------------------+ | slow_query_log | OFF | | slow_query_log_file | /mysql/data/localhost-slow.log | +---------------------------+----------------------------------+mysql> show variables like 'long_query_time'; +-----------------+-----------+ | Variable_name | Value | +-----------------+-----------+ | long_query_time | 10.000000 | +-----------------+-----------+設置方法
方法一:全局變量設置
將 slow_query_log 全局變量設置為“ON”狀態
設置慢查詢日志存放的位置
mysql> set global slow_query_log_file='/usr/local/mysql/data/slow.log';查詢超過1秒就記錄
mysql> set global long_query_time=1;方法二:配置文件設置
修改配置文件my.cnf,在[mysqld]下的下方加入
重啟MySQL服務
service mysqld restart查看設置后的參數
mysql> show variables like 'slow_query%'; +---------------------+--------------------------------+ | Variable_name | Value | +---------------------+--------------------------------+ | slow_query_log | ON | | slow_query_log_file | /usr/local/mysql/data/slow.log | +---------------------+--------------------------------+mysql> show variables like 'long_query_time'; +-----------------+----------+ | Variable_name | Value | +-----------------+----------+ | long_query_time | 1.000000 | +-----------------+----------+測試
1.執行一條慢查詢SQL語句
mysql> select sleep(2);2.查看是否生成慢查詢日志
ls /usr/local/mysql/data/slow.log 3.數據庫優化? 遵循范式? 數據表設計需要遵循方式 首先要符合1NF 才能滿足2NF 進一步滿足3MF 1NF:原子性,不可以在分解 2NF:表中的記錄是惟一的,通常我們設計一個主鍵來實現。 3NF:表中不要亢余數據,就是說表的信息,如果被推導出來,就不應該單獨的設計一個字段來存放(外鍵) 4.選擇合適的存儲引擎 合適存儲引擎:myisam / innodb / memory myisam 存儲引擎: 如果引擎對事務要求不高。一查詢和添加為主。考慮myisam? ? innodb 存儲引擎: 對事物要求高,保存數據為重要數據。 memory存儲引擎: 數據變化頻繁,不需要入庫,同時又頻繁的查詢或修改,我們考慮memory 4.1myisam 與innodb 區別? 1.事務安全myisam 不支持 2.查詢添加速度myisam 更快因為不支持事務 3.支持全文索引?? myisam 支持?innodb 不支持 4.鎖機制 myisam 支持表鎖 而innodb 支持行鎖 5.外鍵 myisam 不支持外鍵?
5.數據庫優化建立合適的索引? 索引是幫助DBMS高效獲取數據的數據結構 普通索引:允許重復的值出現 唯一索引:不能重復值 主鍵索引:是隨著主鍵而創建的。也就是把某個列設為主鍵的時候。數據庫就會把這個列創建索引。主鍵索引唯一而且沒有NULL值 全文索引:用來對表中的文本域進行索引 ? 6.索引的一些小技巧? ?索引弊端 1.占用磁盤空間 2.對dml操作有影響,變慢 使用場景: 1.如果不做查詢就沒有意義 2.該字段的內容不是唯一的幾個值 3.字段內容不頻繁變化?
7.數據庫分表技術? 分表分為水平分表和垂直分表處理。 根據經驗:mysql表中數據一般達到百萬級別,查詢效率會很低。容易造成表鎖。甚至堆積很多銜接。直接掛掉;水平份表能很大程度減少這些壓力 如果一張表字段非常多在少數情況會查詢。這樣就可以這部分字段單獨放在一個表,進行外鍵關聯起來。這種事垂直分表 水平分表策略: 1.按時間分表? 時間分表會有局限性,當數據具有較強的實效性,這種很少有用戶查詢幾個月前的數據就可以進行時間分表 2.按區間范圍分表 有一定嚴格的自增ID需求上? 比如:100-200 200-300 3.Hash區別 ? 通過一個原始目標ID或者名稱通過一定的Hash算法計算出數據存儲標的表名然后進行訪問相應的表 8.數據庫的讀寫分離? ? 對于數據存儲層高并發問題,最先想到的可能就是讀寫分離,在網站訪問量大并且讀寫不平均的情況下,將存儲分為master,slave兩臺,所有的寫都路由到master上,所有的讀都路由到slave上,然后master和slave同步。 在設計讀寫分離的時候,有幾種解決方案: ? ? 1. 將讀寫分離放在dao層,在dao層,?所有的insert/update/delete都訪問master庫,所有的select 都訪問salve庫,這樣對于業務層是透明的。? ? ? 2. 將讀寫分離放在ORM層,比如mybatis可以通過mybatis plus攔截sql語句,所有的insert/update/delete都訪問master庫,所有的select 都訪問salve庫,這樣對于dao層都是透明。? ? ? 3. 放在代理層,比如MySQL-Proxy,這樣針對整個應用程序都是透明的。? 主從同步 數據庫最終會把數據持久化到硬盤,如果集群必須確保每個數據庫服務器的數據是一致的,能改變數據庫數據的操作都是主數據庫來做。而其他的數據庫從主數據庫同步數據。 讀寫分離 使用復雜均衡來實現寫的操作都往主數據庫,而讀的操作往從服務器去。 9.數據庫值緩存 在持久層和數據庫之間添加一個緩存層。如數據訪問數據以及緩存起來。那么用戶直接在緩存中獲取。不用訪問數據庫。 而緩存 是在操作內存級,訪問速度快。 作用:減少數據庫服務器壓力,減少訪問時間。 Java常見二級緩存: hibernate二級緩存,該緩存不能完成分布式緩存 可以使用redis作為中央緩存。 JVM? 1.Minor GC 與 Major GC的區別與意義 Minor GC新生代GC:指發生在新生代的垃圾收集動作。因為Java對象大多數都具有朝生夕滅的特征。所以Minor GC非常頻繁,一般回收速度較快。 Major GC/Full GC老年代GC:指發生在老年代的GC,出現了Major? GC至少伴隨一次Minor GC(但非絕對的,在Parallerl Scavenge收集器的收集策略里就有直接進行Major GC的策略選擇過程),Major GC的速度一般比Minor GC慢10倍以上。 2.JVM堆的三部分:年輕代? 老年代? 永久代(元數據區) 1.年輕代:主要是用來存放新生的對象。內存大小相對會比較小,一般占據堆的1/3空間。由于頻繁創建對象,所以新生代會頻繁觸發MinorGC進行垃圾回收。新生代又分為 Eden區、ServivorFrom、ServivorTo三個區。
Eden區:Java新對象的出生地(如果新創建的對象占用內存很大,則直接分配到老年代)。當Eden區內存不夠的時候就會觸發MinorGC,對新生代區進行一次垃圾回收。
ServivorTo:保留了一次MinorGC過程中的幸存者。
ServivorFrom:上一次GC的幸存者,作為這一次GC的被掃描者。
MinorGC的過程:MinorGC采用復制算法。首先,把Eden和ServivorFrom區域中存活的對象復制到ServicorTo區域(如果有對象的年齡以及達到了老年的標準,則賦值到老年代區),同時把這些對象的年齡+1(如果ServicorTo不夠位置了就放到老年區);然后,清空Eden和ServicorFrom中的對象;最后,ServicorTo和ServicorFrom互換,原ServicorTo成為下一次GC時的ServicorFrom區。
2.老年代:
主要存放應用程序中生命周期長的內存對象。
老年代的對象比較穩定,所以MajorGC不會頻繁執行。在進行MajorGC前一般都先進行了一次MinorGC,使得有新生代的對象晉身入老年代,導致空間不夠用時才觸發。當無法找到足夠大的連續空間分配給新創建的較大對象時也會提前觸發一次MajorGC進行垃圾回收騰出空間。
MajorGC采用標記—清除算法:首先掃描一次所有老年代,標記出存活的對象,然后回收沒有標記的對象。MajorGC的耗時比較長,因為要掃描再回收。MajorGC會產生內存碎片,為了減少內存損耗,我們一般需要進行合并或者標記出來方便下次直接分配。
當老年代也滿了裝不下的時候,就會拋出OOM(Out of Memory)異常。
3.永久代:
指內存的永久保存區域,主要存放Class和Meta(元數據)的信息,Class在被加載的時候被放入永久區域。它和和存放實例的區域不同,GC不會在主程序運行期對永久區域進行清理。所以這也導致了永久代的區域會隨著加載的Class的增多而脹滿,最終拋出OOM異常。
在Java8中,永久代已經被移除,被一個稱為“元數據區”(元空間)的區域所取代。
※:元空間的本質和永久代類似,都是對JVM規范中方法區的實現。不過元空間與永久代之間最大的區別在于:元空間并不在虛擬機中,而是使用本地內存
轉載于:https://www.cnblogs.com/Jonecmnn/p/8557142.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的Java 基础总结。的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 陆军工程大学人防生算军人吗?
- 下一篇: 实战:向GitHub提交代码时触发Jen