面試整理(Java基礎4)

61、編寫多線程程序有幾種實現方式?

一種是繼承 Thread 類;另一種是實現Runnable 接口。Java 5 以後創建線程還有第三種方式:實現 Callable 接口,該接口中的 call方法可以在線程執行結束時產生一個返回值。
Thread和Runnable是實現java多線程的2種方式,runable是接口,thread是類,建議使用runable實現 java多線程,不管如何,最終都需要通過thread.start()來使線程處於可運行狀態。
調用start方法方可啓動線程,而run方法只是thread的一個普通方法調用,還是在主線程裏執行。
把需要並行處理的代碼放在run()方法中,start()方法啓動線程將自動調用 run()方法,這是由jvm的內存機制規定的。並且run()方法必須是public訪問權限,返回值類型爲void.

62、synchronized 關鍵字的用法?

synchronized 關鍵字可以將對象或者方法標記爲同步,以實現對對象和方法的互斥訪問,可以用 synchronized(對象) { … }定義同步代碼塊,或者在聲明方法時將 synchronized 作爲方法的修飾符

63、舉例說明同步和異步。

例如正在寫的數據以後可能被另一個線程讀到,或者正在讀的數據可能已經被另一個線程寫過了,那麼這些數據就必須進行同步存取。當應用程序在對象上調用了一個需要花費很長時間來執行的方法,並且不希望讓程序等待方法的返回時,就應該使用異步編程

64、啓動一個線程是調用 run()還是 start()方法?

啓動一個線程是調用 start()方法,使線程所代表的虛擬處理機處於可運行狀態,這意味着它可以由 JVM 調度並執行,這並不意味着線程就會立即運行。run()方法是線程啓動後要進行回調(callback)的方法。

65、什麼是線程池(thread pool)?

線程池顧名思義就是事先創建若干個可執行的線程放入一個池(容器)中,需要的時候從池中獲取線程不用自行創建,使用完畢不需要銷燬線程而是放回池中,從而減少創建和銷燬線程對象的開銷。Java 5+中的 Executor 接口定義一個執行線程的工具。它的子類型即線程池接口是 ExecutorService。
要配置一個線程池是比較複雜的,尤其是對於線程池的原理不是很清楚的情況下,因此在工具類 Executors 面提供了一些靜態工廠方法,生成一些常用的線程池,如下所示:
(1)newSingleThreadExecutor:創建一個單線程的線程池。這個線程池只有一個線程在工作,也就是相當於單線程串行執行所有任務。如果這個唯一的線程因爲異常結束,那麼會有一個新的線程來替代它。此線程池保證所有任務的執行順序按照任務的提交順序執行。
(2)newFixedThreadPool:創建固定大小的線程池。每次提交一個任務就創建一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,如果某個線程因爲執行異常而結束,那麼線程池會補充一個新線程。
(3) newCachedThreadPool:創建一個可緩存的線程池。如果線程池的大小超過了處理任務所需要的線程,那麼就會回收部分空閒(60 秒不執行任務)的線程,當任務數增加時,此線程池又可以智能的添加新線程來處理任務。此線程池不會對線程池大小做限制,線程池大小完全依賴於操作系統(或者說 JVM)能夠創建的最大線程大小。
(4)newScheduledThreadPool:創建一個大小無限的線程池。此線程池支持定時以及週期性執行任務的需求。
建議使用 newFixedThreadPool方法來創建線程池,這樣能獲得更好的性能。

66、線程的基本狀態以及狀態之間的關係?

67、簡述 synchronized 和 java.util.concurrent.locks.Lock 的異同?

Lock 能完成 synchronized 所實現的所有功能。
Lock 有比synchronized 更精確的線程語義和更好的性能,而且不強制性的要求一定要獲得鎖。synchronized 會自動釋放鎖,而 Lock 一定要求程序員手工釋放,並且最好在 finally 塊中釋放(這是釋放外部資源的最好的地方)。

68、Java 中如何實現序列化,有什麼意義?

序列化是爲了解決對象流讀寫操作時可能引發的問題(如果不進行序列化可能會存在數據亂序的問題)要實現序列化,需要讓一個類實現 Serializable 接口,該接口是一個標識性接口,標註該類對象是可被序列化的,然後使用一個輸出流來構造一個對象輸出流並通過 writeObject(Object)方法就可以將實現對象寫出(即保存其狀態);如果需要反序列化則可以用一個輸入流建立對象輸入流,然後通過 readObject 方法從流中讀取對象。序列化除了能夠實現對象的持久化之外,還能夠用於對象的深度克隆

69、Java 中有幾種類型的流?

字節流和字符流。字節流繼承於 InputStream、OutputStream,字符流繼承於Reader、Writer

70、寫一個方法,輸入一個文件名和一個字符串,統計這個字符串在這個文件中出現的次數。

import java.io.BufferedReader;
import java.io.FileReader;
public final class MyUtil {
	// 工具類中的方法都是靜態方式訪問的因此將構造器私有不允許創建對象
	(絕對好習慣)
	private MyUtil() {
		throw new AssertionError();
	}
	/**
* 統計給定文件中給定字符串的出現次數
*
* @param filename 文件名
* @param word 字符串
* @return 字符串在文件中出現的次數
*/
	public static int countWordInFile(String filename, String word) {
		int counter = 0;
		try (FileReader fr = new FileReader(filename)) {
			try (BufferedReader br = new BufferedReader(fr)) {
				String line = null;
				while ((line = br.readLine()) != null) {
					int index = -1;
					while (line.length() >= word.length() && (index =
					line.indexOf(word)) >= 0) {
						counter++;
						line = line.substring(index + word.length());
					}
				}
			}
		}
		catch (Exception ex) {
			ex.printStackTrace();
		}
		return counter;
	}
}

71、如何用 Java 代碼列出一個目錄下所有的文件?

import java.io.File;
class Test12 {
	public static void main(String[] args) {
		File f = new File("/Users/Hao/Downloads");
		for (File temp : f.listFiles()) {
			if(temp.isFile()) {
				System.out.println(temp.getName());
			}
		}
	}
}

72、XML 文檔定義有幾種形式?它們之間有何本質區別?解析 XML文檔有哪幾種方式?

XML 文檔定義分爲 DTD 和 Schema 兩種形式,二者都是對 XML 語法的約束,其本質區別在於 Schema 本身也是一個 XML 文件,可以被 XML 解析器解析,而且可以爲 XML 承載的數據定義類型,約束能力較之 DTD 更強大。
對 XML 的解析主要有
 
DOM(文檔對象模型,Document Object Model):
DOM 處理大型文件時其性能下降的非常厲害,這個問題是由 DOM 樹結構佔用的內存較多造成的,而且 DOM 解析方式必須在解析文件之前把整個文檔裝入內存,適合對 XML 的隨機訪問(典型的用空間換取時間的策略);
SAX(Simple API forXML):
SAX 是事件驅動型的 XML 解析方式,它順序讀取 XML 文件,不需要一次全部裝載整個文件。當遇到像文件開頭,文檔結束,或者標籤開頭與標籤結束時,它會觸發一個事件,用戶通過事件回調代碼來處理 XML 文件,適合對 XML 的順序訪問;
 
StAX(Java 6 中引入的新的解析 XML 的方式,Streaming API for XML)StAX 把重點放在流上,實際上 StAX 與其他解析方式的本質區別就在於應用程序能夠把 XML 作爲一個事件流來處理。將 XML 作爲一組事件來處理的想法並不新穎( SAX 就是這樣做的),但不同之處在於 StAX 允許應用程序代碼把這些事件逐個拉出來,而不用提供在解析器方便時從解析器中接收事件的處理程序。
》》》》詳細可見

75、Statement 和 PreparedStatement 有什麼區別?哪個性能更好?

與 Statement 相比,①PreparedStatement 接口代表預編譯的語句,它主要的優勢在於可以減少 SQL 的編譯錯誤並增加 SQL 的安全性(減少 SQL 注射攻擊的可能性);②PreparedStatement 中的 SQL 語句是可以帶參數的,避免了用字符串連接拼接 SQL 語句的麻煩和不安全;③當批量處理 SQL 或頻繁執行相同的查詢時,PreparedStatement 有明顯的性能上的優勢,由於數據庫可以將編譯優化後的SQL 語句緩存起來,下次執行相同結構的語句時就會很快(不用再次編譯和生成執行計劃)

76、使用 JDBC 操作數據庫時,如何提升讀取數據的性能?如何提升更新數據的性能?

要提升讀取數據的性能,可以指定通過結果集(ResultSet)對象的 setFetchSize()方法指定每次抓取的記錄數(典型的空間換時間策略);要提升更新數據的性能可以使用 PreparedStatement 語句構建批處理,將若干 SQL 語句置於一個批處理中執行。

77、事務的 ACID 是指什麼?

(1)原子性(Atomic):事務中各項操作,要麼全做要麼全不做,任何一項操作的失敗都會導致整個事務的失敗;(2)一致性(Consistent):事務結束後系統狀態是一致的;(3)隔離性(Isolated):併發執行的事務彼此無法看到對方的中間狀態;(4)持久性(Durable):事務完成後所做的改動都會被持久化,即使發生災難性的失敗。通過日誌和同步備份可以在故障發生後重建數據。

ConcurrentHashMap,HashMap與HashTable,ArrayList和LinkList,Vector,Collection和Collections的區別:

> 這裏是引用
ConcurrentHashMap,HashMap與HashTable:

  1. collection是最基本的集合集合接口。Map不繼承與collection
    Collection是接口是各種集合的父接口,conllections是類主要是集合的增刪改查的方法
    set中的對象是不允許重複的,無序的,TreeSet可排序
    list中的對象是允許重複的,有序的。List與數組有些相似,有下標的概念。
    map中的對象是按照key-value存儲的,key不可以重複,value可以重複。【Map沒有繼承Collection接口
     
    HashMap與HashTable的區別:
  2. HashMap:
    線程不安全的不同步的。默認容量是16。 負載因子默認是0.75
    可以將null作爲key或者value。
    實際上是一個連續的鏈表數組,通過key值的hash值來確定對應的index,如果發生碰撞那就二次hash來避免碰撞。使用的是 Iterator迭代器
  3. HashTable
    作鍵的對象必須重寫equals和hashCode方法。是線程安全的同步的,
    默認容量是11。擴容是(old*2+1), 容量而且一定是2的指數
    使用的是 Enumeration迭代器
     
  4. SynchronizedMap
    就是在HashMap上加了個鎖,性能不必HashTable強
     
  5. ConcurrentHashMap:
  • 線程安全的,把hash表分成了16份Segment,當作刪除,添加修改操作的時候數據在哪一段就鎖住那一段,故可以16個線程並行執行,所以要比HashTable的效率快16倍。但是當執行size操作的時候還是整表鎖住的。鎖的粒度要細的多。
     
  • JDK1.8的實現降低鎖的粒度,JDK1.7版本鎖的粒度是基於Segment的,包含多個HashEntry,而JDK1.8鎖的粒度就是HashEntry(首節點)
     
  • JDK1.8版本的數據結構變得更加簡單,使得操作也更加清晰流暢,因爲已經使用synchronized來進行同步,所以不需要分段鎖的概念,也就不需要Segment這種數據結構了,由於粒度的降低,實現的複雜度也增加了
     
  • JDK1.8使用紅黑樹來優化鏈表,基於長度很長的鏈表的遍歷是一個很漫長的過程,而紅黑樹的遍歷效率是很快的,代替一定閾值的鏈表,這樣形成一個最佳拍檔
     
  • JDK1.8爲什麼使用內置鎖synchronized來代替重入鎖ReentrantLock,我覺得有以下幾點
     
    • 因爲粒度降低了,在相對而言的低粒度加鎖方式,synchronized並不比ReentrantLock差,在粗粒度加鎖中ReentrantLock可能通過Condition來控制各個低粒度的邊界,更加的靈活,而在低粒度中,Condition的優勢就沒有了
       
    • JVM的開發團隊從來都沒有放棄synchronized,而且基於JVM的synchronized優化空間更大,使用內嵌的關鍵字比使用API更加自然
      在大量的數據操作下,對於JVM的內存壓力,基於API的ReentrantLock會開銷更多的內存,雖然不是瓶頸,但是也是一個選擇依據

ArrayList和LinkList,Vector的區別

1)都是list接口的實現類
2)vector是線程安全的同步的,arrayList不是的。
3)當數據增長的時候vector默認增長一倍,arrayList默認是一半
4)LinkedList 使用雙向鏈表實現存儲,按序號索引數據需要進行前向或後向遍歷(尋址),
但是插入數據時只需要記錄本項的前後項即可,所以 插入速度較快而循環數據慢
5)ArrayList和 Vector都是使用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增加和插入元素,
它們都允許直接按序號索引元素,但是插入元素要涉及數組元素移動等內存操作,所以循環數據快而插入數據慢

判斷set元素是否重複:

Set是使用iterator()方法來區分重複與否, equals()是判斷兩個Set是否相等。重寫了equals()

》》》》》》》》》》》》》面試整理(Java基礎3)
》》》》》》》》》》》》》面試整理(Java基礎5)

轉載自:https://juejin.im/post/5decd3e16fb9a0164d45f999#heading-2

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