Java 八股文

一淹仑、Java 基礎(chǔ)知識

1匀借、Object 類相關(guān)方法

  • getClass
    獲取當(dāng)前運(yùn)行時對象的 Class 對象吓肋。
  • hashCode
    返回對象的 hash 碼。
  • clone
    拷貝當(dāng)前對象肤舞, 必須實(shí)現(xiàn) Cloneable 接口李剖。淺拷貝對基本類型進(jìn)行值拷貝囤耳,對引用類型拷貝引用;深拷貝對基本類型進(jìn)行值拷貝充择,對引用類型對象不但拷貝對象的引用還拷貝對象的相關(guān)屬性和方法。兩者不同在于深拷貝創(chuàng)建了一個新的對象。
  • equals
    通過內(nèi)存地址比較兩個對象是否相等铃剔,String 類重寫了這個方法使用值來比較是否相等键兜。
  • toString
    返回類名@哈希碼的 16 進(jìn)制穗泵。
  • notify
    喚醒當(dāng)前對象監(jiān)視器的任一個線程佃延。
  • notifyAll
    喚醒當(dāng)前對象監(jiān)視器上的所有線程履肃。
  • wait
    1尺棋、暫停線程的執(zhí)行;2成福、三個不同參數(shù)方法(等待多少毫秒奴艾;額外等待多少毫秒握侧;一直等待)3品擎、與 Thread.sleep(long time) 相比萄传,sleep 使當(dāng)前線程休眠一段時間,并沒有釋放該對象的鎖振诬,wait 釋放了鎖赶么。
  • finalize
    對象被垃圾回收器回收時執(zhí)行的方法辫呻。

2放闺、基本數(shù)據(jù)類型

  • 整型:byte(8)怖侦、short(16)谜叹、int(32)叉谜、long(64)
  • 浮點(diǎn)型:float(32)停局、double(64)
  • 布爾型:boolean(8)
  • 字符型:char(16)

3、序列化

Java 對象實(shí)現(xiàn)序列化要實(shí)現(xiàn) Serializable 接口企孩。

  • 反序列化并不會調(diào)用構(gòu)造方法勿璃。反序列的對象是由 JVM 自己生成的對象推汽,不通過構(gòu)造方法生成歹撒。
  • 序列化對象的引用類型成員變量暖夭,也必須是可序列化的迈着,否則裕菠,會報錯。
  • 如果想讓某個變量不被序列化枫振,使用 transient 修飾。
  • 單例類序列化雀扶,需要重寫 readResolve() 方法愚墓。

4浪册、String村象、StringBuffer厚者、StringBuilder

  • String
    由 char[] 數(shù)組構(gòu)成,使用了 final 修飾账忘,是不可變對象鳖擒,可以理解為常量蒋荚,線程安全圆裕;對 String 進(jìn)行改變時每次都會新生成一個 String 對象吓妆,然后把指針指向新的引用對象行拢。
  • StringBuffer 線程安全舟奠;StringBuiler 線程不安全沼瘫。
  • 操作少量字符數(shù)據(jù)用 String耿戚;單線程操作大量數(shù)據(jù)用 StringBuilder膜蛔;多線程操作大量數(shù)據(jù)用 StringBuffer脖阵。

5命黔、重載與重寫

  • 重載
    發(fā)生在同一個類中,方法名相同战转,參數(shù)的類型槐秧、個數(shù)刁标、順序不同膀懈,方法的返回值和修飾符可以不同启搂。
  • 重寫
    發(fā)生在父子類中胳赌,方法名和參數(shù)相同疑苫,返回值范圍小于等于父類捍掺,拋出的異常范圍小于等于父類挺勿,訪問修飾符范圍大于等于父類满钟;如果父類方法訪問修飾符為 private 或者 final 則子類就不能重寫該方法。

6吭露、final

  • 修飾基本類型變量讲竿,一經(jīng)出初始化后就不能夠?qū)ζ溥M(jìn)行修改题禀。
  • 修飾引用類型變量,不能夠指向另一個引用削彬。
  • 修飾類或方法,不能被繼承或重寫雁刷。

7沛励、反射

  • 在運(yùn)行時動態(tài)的獲取類的完整信息
  • 增加程序的靈活性
  • JDK 動態(tài)代理使用了反射

8目派、JDK 動態(tài)代理

  • 使用步驟
    • 創(chuàng)建接口及實(shí)現(xiàn)類
    • 實(shí)現(xiàn)代理處理器:實(shí)現(xiàn) InvokationHandler 址貌,實(shí)現(xiàn) invoke(Proxy proxy练对,Method method螟凭,Object[] args) 方法
    • 通過 Proxy.newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h) 獲得代理類
    • 通過代理類調(diào)用方法螺男。

9下隧、Java IO

  • 普通 IO 淆院,面向流土辩,同步阻塞線程拷淘。
  • NIO启涯,面向緩沖區(qū)逝嚎,同步非阻塞补君。

二挽铁、Java 集合框架

1叽掘、List(線性結(jié)構(gòu))

  • ArrayList
    Object[] 數(shù)組實(shí)現(xiàn)更扁,默認(rèn)大小為 10 浓镜,支持隨機(jī)訪問膛薛,連續(xù)內(nèi)存空間哄啄,插入末尾時間復(fù)雜度 o(1)咨跌,插入第 i 個位置時間復(fù)雜度 o(n - i)锌半。擴(kuò)容,大小變?yōu)?1.5 倍,Arrays.copyOf(底層 System.ArrayCopy)钦勘,復(fù)制到新數(shù)組,指針指向新數(shù)組肛响。
  • Vector
    類似 ArrayList特笋,線程安全猎物,擴(kuò)容默認(rèn)增長為原來的 2 倍蔫磨,還可以指定增長空間長度堤如。
  • LinkedList
    基于鏈表實(shí)現(xiàn)搀罢,1.7 為雙向鏈表魄揉,1.6 為雙向循環(huán)鏈表洛退,取消循環(huán)更能分清頭尾省有。

2、Map(K辆毡,V 對)

  • HashMap
    • 底層數(shù)據(jù)結(jié)構(gòu),JDK 1.8 是數(shù)組 + 鏈表 + 紅黑樹奠货,JDK 1.7 無紅黑樹递惋。鏈表長度大于 8 時萍虽,轉(zhuǎn)化為紅黑樹,優(yōu)化查詢效率王财。
    • 初始容量為 16绒净,通過 tableSizeFor 保證容量為 2 的冪次方挂疆。尋址方式缤言,高位異或胆萧,(n-1)&h 取模跌穗,優(yōu)化速度。
    • 擴(kuò)容機(jī)制羹唠,當(dāng)元素數(shù)量大于容量 x 負(fù)載因子 0.75 時佩微,容量擴(kuò)大為原來的 2 倍哺眯,新建一個數(shù)組,然后轉(zhuǎn)移到新數(shù)組寝杖。
    • 基于 Map 實(shí)現(xiàn)。
    • 線程不安全互纯。
  • HashMap (1.7) 多線程循環(huán)鏈表問題
    • 在多線程環(huán)境下瑟幕,進(jìn)行擴(kuò)容時,1.7 下的 HashMap 會形成循環(huán)鏈表留潦。
    • 怎么形成循環(huán)鏈表:
      假設(shè)有一 HashMap 容量為 2 只盹, 在數(shù)組下標(biāo) 1 位置以 A -> B 鏈表形式存儲兔院。有一線程對該 map 做 put 操作殖卑,由于觸發(fā)擴(kuò)容條件,需要進(jìn)行擴(kuò)容坊萝。這時另一個線程也 put 操作孵稽,同樣需要擴(kuò)容,并完成了擴(kuò)容操作十偶,由于復(fù)制到新數(shù)組是頭部插入菩鲜,所以 1 位置變?yōu)?B -> A 。這時第一個線程繼續(xù)做擴(kuò)容操作惦积,首先復(fù)制 A 接校,然后復(fù)制 B ,再判斷 B.next 是否為空時狮崩,由于第二個線程做了擴(kuò)容操作蛛勉,導(dǎo)致 B.next = A,所以在將 A 放到 B 前厉亏,A.next 又等于 B 董习,導(dǎo)致循環(huán)鏈表出現(xiàn)。
  • HashTable
    • 線程安全爱只,方法基本全用 Synchronized 修飾皿淋。
    • 初始容量為 11 招刹,擴(kuò)容為 2n + 1 。
    • 繼承 Dictionary 類窝趣。
  • ConcurrentHashMap
    • 線程安全的 HashMap疯暑。
    • 1.7 采用分段鎖的形式加鎖;1.8 使用 Synchronized 和 CAS 實(shí)現(xiàn)同步哑舒,若數(shù)組的 Node 為空妇拯,則通過 CAS 的方式設(shè)置值,不為空則加在鏈表的第一個節(jié)點(diǎn)洗鸵。獲取第一個元素是否為空使用 Unsafe 類提供的 getObjectVolatile 保證可見性越锈。
    • 對于讀操作,數(shù)組由 volatile 修飾膘滨,同時數(shù)組的元素為 Node甘凭,Node 的 K 使用 final 修飾,V 使用 volatile 修飾火邓,下一個節(jié)點(diǎn)也用 volatile 修飾丹弱,保證多線程的可見性。
  • LinkedHashMap
    LinkedHashMap 繼承自 HashMap铲咨,所以它的底層仍然是基于拉鏈?zhǔn)缴⒘薪Y(jié)構(gòu)即由數(shù)組和鏈表或紅黑樹組成躲胳。另外,LinkedHashMap 在上面結(jié)構(gòu)的基礎(chǔ)上纤勒,增加了一條雙向鏈表坯苹,使得上面的結(jié)構(gòu)可以保持鍵值對的插入順序。
  • TreeMap
    有序的 Map摇天,紅黑樹結(jié)構(gòu)北滥,可以自定義比較器來進(jìn)行排序。
  • Collections.synchronizedMap 如何實(shí)現(xiàn) Map 線程安全闸翅?
    基于 Synchronized 再芋,實(shí)際上就是鎖住了當(dāng)前傳入的 Map 對象。

3坚冀、Set(唯一值)

  • HashSet
    基于 HashMap 實(shí)現(xiàn)济赎,使用了 HashMap 的 K 作為元素存儲,V 為 new Object() 记某,在 add() 方法中如果兩個元素的 Hash 值相同司训,則通過 equals 方法比較是否相等。
  • LinkedHashSet
    LinkedHashSet 繼承于 HashSet液南,并且其內(nèi)部是通過 LinkedHashMap 來實(shí)現(xiàn)的壳猜。
  • TreeSet
    紅黑樹實(shí)現(xiàn)有序唯一。

三滑凉、Java 多線程

1统扳、synchronized

  • 修飾代碼塊
    底層實(shí)現(xiàn)喘帚,通過 monitorenter & monitorexit 標(biāo)志代碼塊為同步代碼塊。
  • 修飾方法
    底層實(shí)現(xiàn)咒钟,通過 ACC_SYNCHRONIZED 標(biāo)志方法是同步方法吹由。
  • 修飾類 class 對象時,實(shí)際鎖在類的實(shí)例上面朱嘴。
  • 單例模式
public class Singleton {

    private static volatile Singleton instance = null;

    private Singleton(){}

    public static Singleton getInstance(){
    if (null == instance) {
        synchronized (Singleton.class) {
            if (null == instance) {
            instance = new Singleton();
            }
        }
      }
        return instance;
        }
}
  • 偏向鎖倾鲫,自旋鎖,輕量級鎖萍嬉,重量級鎖
    • 通過 synchronized 加鎖乌昔,第一個線程獲取的鎖為偏向鎖,這時有其他線程參與鎖競爭壤追,升級為輕量級鎖玫荣,其他線程通過循環(huán)的方式嘗試獲得鎖,稱自旋鎖大诸。若果自旋的次數(shù)達(dá)到一定的閾值,則升級為重量級鎖贯卦。
    • 需要注意的是资柔,在第二個線程獲取鎖時,會先判斷第一個線程是否仍然存活撵割,如果不存活贿堰,不會升級為輕量級鎖。

2啡彬、Lock

  • ReentrantLock
    • 基于 AQS (AbstractQueuedSynchronizer)實(shí)現(xiàn)羹与,主要有 state (資源) + FIFO (線程等待隊(duì)列) 組成。
    • 公平鎖與非公平鎖:區(qū)別在于在獲取鎖時庶灿,公平鎖會判斷當(dāng)前隊(duì)列是否有正在等待的線程纵搁,如果有則進(jìn)行排隊(duì)。
    • 使用 lock() 和 unLock() 方法來加鎖解鎖往踢。
  • ReentrantReadWriteLock
    • 同樣基于 AQS 實(shí)現(xiàn)腾誉,內(nèi)部采用內(nèi)部類的形式實(shí)現(xiàn)了讀鎖(共享鎖)和寫鎖 (排它鎖)。
  • 非公平鎖吞吐量高
    在獲取鎖的階段來分析峻呕,當(dāng)某一線程要獲取鎖時利职,非公平鎖可以直接嘗試獲取鎖,而不是判斷當(dāng)前隊(duì)列中是否有線程在等待瘦癌。一定情況下可以避免線程頻繁的上下文切換猪贪,這樣,活躍的線程有可能獲得鎖讯私,而在隊(duì)列中的鎖還要進(jìn)行喚醒才能繼續(xù)嘗試獲取鎖热押,而且線程的執(zhí)行順序一般來說不影響程序的運(yùn)行西傀。

3、volatile

  • Java 內(nèi)存模型
image.png
  • 在多線程環(huán)境下楞黄,保證變量的可見性池凄。使用了 volatile 修飾變量后,在變量修改后會立即同步到主存中鬼廓,每次用這個變量前會從主存刷新肿仑。
  • 禁止 JVM 指令重排序。
  • 單例模式雙重校驗(yàn)鎖變量為什么使用 volatile 修飾碎税?
    禁止 JVM 指令重排序尤慰,new Object()分為三個步驟:申請內(nèi)存空間,將內(nèi)存空間引用賦值給變量雷蹂,變量初始化伟端。如果不禁止重排序,有可能得到一個未經(jīng)初始化的變量匪煌。

4责蝠、線程的五種狀態(tài)

1). New

一個新的線程被創(chuàng)建,還沒開始運(yùn)行萎庭。

2). Runnable

一個線程準(zhǔn)備就緒霜医,隨時可以運(yùn)行的時候就進(jìn)入了 Runnable 狀態(tài)。

Runnable 狀態(tài)可以是實(shí)際正在運(yùn)行的線程驳规,也可以是隨時可以運(yùn)行的線程肴敛。

多線程環(huán)境下,每個線程都會被分配一個固定長度的 CPU 計算時間吗购,每個線程運(yùn)行一會兒就會停止讓其他線程運(yùn)行医男,這樣才能讓每個線程公平的運(yùn)行。這些等待 CPU 和正在運(yùn)行的線程就處于 Runnable 狀態(tài)捻勉。

3). Blocked

例如一個線程在等待 I/O 資源镀梭,或者它要訪問的被保護(hù)代碼已經(jīng)被其他線程鎖住了,那么它就在阻塞 Blocked 狀態(tài)踱启,這個線程所需的資源到位后就轉(zhuǎn)入 Runnable 狀態(tài)丰辣。

4). Waiting(無限期等待)

如果一個線程在等待其他線程的喚醒,那么它就處于 Waiting 狀態(tài)禽捆。以下方法會讓線程進(jìn)入等待狀態(tài):

  • Object.wait()
  • Thread.join()
  • LockSupport.park()
5). Timed Waiting(有期限等待)

無需等待被其他線程顯示喚醒笙什,在一定時間后有系統(tǒng)自動喚醒。

以下方法會讓線程進(jìn)入有限等待狀態(tài):

  • Thread.sleep(sleeptime)
  • Object.wait(timeout)
  • Thread.join(timeout)
  • LockSupport.parkNanos(timeout)
  • LockSupport.parkUntil(timeout)
6). Terminated

一個線程正常執(zhí)行完畢胚想,或者意外失敗琐凭,那么就結(jié)束了。

5浊服、 wait() 與 sleep()

  • 調(diào)用后線程進(jìn)入 waiting 狀態(tài)统屈。
  • wait() 釋放鎖胚吁,sleep() 沒有釋放鎖。
  • 調(diào)用 wait() 后需要調(diào)用 notify() 或 notifyAll() 方法喚醒線程愁憔。
  • wait() 方法聲明在 Object 中腕扶,sleep() 方法聲明在 Thread 中。

6吨掌、 yield()

  • 調(diào)用后線程進(jìn)入 runnable 狀態(tài)半抱。
  • 讓出 CPU 時間片,之后有可能其他線程獲得執(zhí)行權(quán)膜宋,也有可能這個線程繼續(xù)執(zhí)行窿侈。

7、 join()

  • 在線程 B 中調(diào)用了線程 A 的 Join()方法秋茫,直到線程 A 執(zhí)行完畢后史简,才會繼續(xù)執(zhí)行線程 B。
  • 可以保證線程的順序執(zhí)行肛著。
  • join() 方法必須在 線程啟動后調(diào)用才有意義圆兵。
  • 使用 wait() 方法實(shí)現(xiàn)。

9枢贿、線程使用方式

  • 繼承 Tread 類
  • 實(shí)現(xiàn) Runnable 接口
  • 實(shí)現(xiàn) Callable 接口:帶有返回值

10殉农、Runnable 和 Callable 比較

  1. 方法簽名不同, void Runnable.run() , V Callable.call() throws Exception
  2. 是否允許有返回值萨咕, Callable 允許有返回值
  3. 是否允許拋出異常, Callable 允許拋出異常火本。
  4. 提交任務(wù)方式危队, Callable 使用 Future<T> submit(Callable<T> task) 返回 Future 對象,調(diào)用其 get() 方法可以獲得返回值钙畔, Runnable 使用 void execute(Runnable command) 茫陆。

11、hapens-before

如果一個操作 happens-before 另一個操作擎析,那么第一個操作的執(zhí)行結(jié)果將對第二個操作可見簿盅,而且第一個操作的執(zhí)行順序排在第二個操作之前。

12揍魂、ThreadLocal

  • 場景
    主要用途是為了保持線程自身對象和避免參數(shù)傳遞桨醋,主要適用場景是按線程多實(shí)例(每個線程對應(yīng)一個實(shí)例)的對象的訪問,并且這個對象很多地方都要用到现斋。
  • 原理
    為每個線程創(chuàng)建變量副本喜最,不同線程之間不可見,保證線程安全庄蹋。使用 ThreadLocalMap 存儲變量副本瞬内,以 ThreadLocal 為 K迷雪,這樣一個線程可以擁有多個 ThreadLocal 對象。
  • 實(shí)際
    使用多數(shù)據(jù)源時虫蝶,需要根據(jù)數(shù)據(jù)源的名字切換數(shù)據(jù)源章咧,假設(shè)一個線程設(shè)置了一個數(shù)據(jù)源,這個時候就有可能有另一個線程去修改數(shù)據(jù)源能真,可以使用 ThreadLocal 維護(hù)這個數(shù)據(jù)源名字赁严,使每個線程持有數(shù)據(jù)源名字的副本,避免線程安全問題舟陆。

8误澳、線程池

1)、分類
  • FixThreadPool 固定數(shù)量的線程池秦躯,適用于對線程管理忆谓,高負(fù)載的系統(tǒng)
  • SingleThreadPool 只有一個線程的線程池,適用于保證任務(wù)順序執(zhí)行
  • CacheThreadPool 創(chuàng)建一個不限制線程數(shù)量的線程池踱承,適用于執(zhí)行短期異步任務(wù)的小程序倡缠,低負(fù)載系統(tǒng)
  • ScheduledThreadPool 定時任務(wù)使用的線程池,適用于定時任務(wù)
2)茎活、線程池的幾個重要參數(shù)
  • int corePoolSize, 核心線程數(shù)
  • int maximumPoolSize, 最大線程數(shù)
  • long keepAliveTime, TimeUnit unit, 超過 corePoolSize 的線程的存活時長昙沦,超過這個時間,多余的線程會被回收载荔。
  • BlockingQueue<Runnable> workQueue, 任務(wù)的排隊(duì)隊(duì)列
  • ThreadFactory threadFactory, 新線程的產(chǎn)生方式
  • RejectedExecutionHandler handler) 拒絕策略
3)盾饮、線程池線程工作過程

corePoolSize -> 任務(wù)隊(duì)列 -> maximumPoolSize -> 拒絕策略

核心線程在線程池中一直存活,當(dāng)有任務(wù)需要執(zhí)行時懒熙,直接使用核心線程執(zhí)行任務(wù)丘损。當(dāng)任務(wù)數(shù)量大于核心線程數(shù)時,加入等待隊(duì)列工扎。當(dāng)任務(wù)隊(duì)列數(shù)量達(dá)到隊(duì)列最大長度時徘钥,繼續(xù)創(chuàng)建線程,最多達(dá)到最大線程數(shù)肢娘。當(dāng)設(shè)置回收時間時呈础,核心線程以外的空閑線程會被回收。如果達(dá)到了最大線程數(shù)還不能夠滿足任務(wù)執(zhí)行需求橱健,則根據(jù)拒絕策略做拒絕處理而钞。

4)、線程池拒絕策略(默認(rèn)拋出異常)

|:---|:---|
| AbortPolicy | 拋出 RejectedExecutionException |
| DiscardPolicy | 什么也不做拘荡,直接忽略 |
| DiscardOldestPolicy | 丟棄執(zhí)行隊(duì)列中最老的任務(wù)笨忌,嘗試為當(dāng)前提交的任務(wù)騰出位置 |
| CallerRunsPolicy | 直接由提交任務(wù)者執(zhí)行這個任務(wù) |

5)、如何根據(jù) CPU 核心數(shù)設(shè)計線程池線程數(shù)量
  • IO 密集型 2nCPU
  • 計算密集型 nCPU+1
    • 其中 n 為 CPU 核心數(shù)量,可通過 Runtime.getRuntime().availableProcessors() 獲得核心數(shù):官疲。
    • 為什么加 1:即使當(dāng)計算密集型的線程偶爾由于缺失故障或者其他原因而暫停時袱结,這個額外的線程也能確保 CPU 的時鐘周期不會被浪費(fèi)。

四途凫、Java 虛擬機(jī)

1垢夹、Java 內(nèi)存結(jié)構(gòu)

image.png

  • 由線程共享,存放 new 出來的對象维费,是垃圾回收器的主要工作區(qū)域果元。

  • 線程私有,分為 Java 虛擬機(jī)棧和本地方法棧犀盟,存放局部變量表而晒、操作棧、動態(tài)鏈接阅畴、方法出口等信息倡怎,方法的執(zhí)行對應(yīng)著入棧到出棧的過程。
  • 方法區(qū)
    線程共享贱枣,存放已被加載的類信息监署、常量、靜態(tài)變量纽哥、即時編譯器編譯后的代碼等信息钠乏,JDK 1.8 中方法區(qū)被元空間取代,使用直接內(nèi)存春塌。

2晓避、Java 類加載機(jī)制

image.png
  • 加載
    加載字節(jié)碼文件。
  • 鏈接
    • 驗(yàn)證
      驗(yàn)證字節(jié)碼文件的正確性只壳。
    • 準(zhǔn)備
      為靜態(tài)變量分配內(nèi)存俏拱。
    • 解析
      將符號引用(如類的全限定名)解析為直接引用(類在實(shí)際內(nèi)存中的地址)。
  • 初始化
    為靜態(tài)變量賦初值吕世。

雙親委派模式

當(dāng)一個類需要加載時彰触,判斷當(dāng)前類是否被加載過梯投。已經(jīng)被加載的類會直接返回命辖,否則才會嘗試加載。加載的時候分蓖,首先會把該請求委派該父類加載器的 loadClass() 處理尔艇,因此所有的請求最終都應(yīng)該傳送到頂層的啟動類加載器 BootstrapClassLoader 中。當(dāng)父類加載器無法處理時么鹤,才由自己來處理终娃。當(dāng)父類加載器為 null 時,會使用啟動類加載器 BootstrapClassLoader 作為父類加載器蒸甜。

3棠耕、垃圾回收算法

  • Mark-Sweep(標(biāo)記-清除)算法
    標(biāo)記需要回收的對象余佛,然后清除,會造成許多內(nèi)存碎片窍荧。
  • Copying(復(fù)制)算法
    將內(nèi)存分為兩塊辉巡,只使用一塊,進(jìn)行垃圾回收時蕊退,先將存活的對象復(fù)制到另一塊區(qū)域郊楣,然后清空之前的區(qū)域。
  • Mark-Compact(標(biāo)記-整理)算法(壓縮法)
    與標(biāo)記清除算法類似瓤荔,但是在標(biāo)記之后输硝,將存活對象向一端移動放椰,然后清除邊界外的垃圾對象。
  • Generational Collection(分代收集)算法
    分為年輕代和老年代如蚜,年輕代時比較活躍的對象,使用復(fù)制算法做垃圾回收。老年代每次回收只回收少量對象魂拦,使用標(biāo)記整理法芯勘。

4荷愕、典型垃圾回收器

  • CMS

    • 簡介
      以獲取最短回收停頓時間為目標(biāo)的收集器安疗,它是一種并發(fā)收集器蝶桶,采用的是 Mark-Sweep 算法。
    • 場景
      如果你的應(yīng)用需要更快的響應(yīng)恢共,不希望有長時間的停頓癣蟋,同時你的 CPU 資源也比較豐富疯搅,就適合適用 CMS 收集器幔欧。
    • 垃圾回收步驟
    1. 初始標(biāo)記 (Stop the World 事件 CPU 停頓, 很短) 初始標(biāo)記僅標(biāo)記一下 GC Roots 能直接關(guān)聯(lián)到的對象晒骇,速度很快洪囤;
    2. 并發(fā)標(biāo)記 (收集垃圾跟用戶線程一起執(zhí)行) 并發(fā)標(biāo)記過程就是進(jìn)行 GC Roots 查找的過程;
    3. 重新標(biāo)記 (Stop the World 事件 CPU 停頓箍鼓,比初始標(biāo)記稍微長崭参,遠(yuǎn)比并發(fā)標(biāo)記短) 修正由于并發(fā)標(biāo)記時應(yīng)用運(yùn)行產(chǎn)生變化的標(biāo)記。
    4. 并發(fā)清理,標(biāo)記清除算法奄喂;
    • 缺點(diǎn)
      • 并發(fā)標(biāo)記時和應(yīng)用程序同時進(jìn)行跨新,占用一部分線程,所以吞吐量有所下降肖揣。
      • 并發(fā)清除時和應(yīng)用程序同時進(jìn)行羊异,這段時間產(chǎn)生的垃圾就要等下一次 GC 再清除。
      • 采用的標(biāo)記清除算法彤断,產(chǎn)生內(nèi)存碎片野舶,如果要新建大對象,會提前觸發(fā) Full GC 宰衙。
  • G1

    • 簡介
      是一款面向服務(wù)端應(yīng)用的收集器平道,它能充分利用多 CPU、多核環(huán)境供炼。因此它是一款并行與并發(fā)收集器巢掺,并且它能建立可預(yù)測的停頓時間模型,即可以設(shè)置 STW 的時間劲蜻。
    • 垃圾回收步驟
      1陆淀、初始標(biāo)記(stop the world 事件 CPU 停頓只處理垃圾);
      2先嬉、并發(fā)標(biāo)記(與用戶線程并發(fā)執(zhí)行)轧苫;
      3、最終標(biāo)記(stop the world 事件 ,CPU 停頓處理垃圾)疫蔓;
      4含懊、篩選回收(stop the world 事件 根據(jù)用戶期望的 GC 停頓時間回收)
    • 特點(diǎn)
      • 并發(fā)與并行
        充分利用多核 CPU ,使用多核來縮短 STW 時間衅胀,部分需要停頓應(yīng)用線程的操作岔乔,仍然可以通過并發(fā)保證應(yīng)用程序的執(zhí)行。
      • 分代回收
        新生代滚躯,幸存帶雏门,老年代
      • 空間整合
        總體看是采用標(biāo)記整理算法回收嘿歌,每個 Region 大小相等,通過復(fù)制來回收茁影。
      • 可預(yù)測的停頓時間
        使用 -XX:MaxGCPauseMillis=200 設(shè)置最長目標(biāo)暫停值宙帝。

在 Java 語言中,可作為 GC Roots 的對象包括 4 種情況:

a) 虛擬機(jī)棧中引用的對象(棧幀中的本地變量表)募闲;
b) 方法區(qū)中類靜態(tài)屬性引用的對象步脓;
c) 方法區(qū)中常量引用的對象;
d) 本地方法棧中 Native 方法引用的對象浩螺。

五靴患、MySQL (Inno DB)

1、聚簇索引與非聚簇索引

image.png
  • 都使用 B+ 樹作為數(shù)據(jù)結(jié)構(gòu)
  • 聚簇索引中數(shù)據(jù)存在主鍵索引的葉子結(jié)點(diǎn)中要出,得到 key 即得到 data 蚁廓;非聚簇索引的數(shù)據(jù)存在單獨(dú)的空間。
  • 聚簇索引中輔助索引的葉子結(jié)點(diǎn)存的是主鍵厨幻;非聚簇索引中葉子結(jié)點(diǎn)存的是數(shù)據(jù)的地址相嵌;
  • 聚簇索引的優(yōu)勢是找到主鍵就找到數(shù)據(jù),只需一次磁盤 IO 况脆;當(dāng) B+ 樹的結(jié)點(diǎn)發(fā)生變化時饭宾,地址也會發(fā)生變化,這時非聚簇索引需要更新所有的地址格了,增加開銷看铆。

2、為何使用 B 樹做索引而不是紅黑樹盛末?

索引很大弹惦,通常作為文件存儲在磁盤上面,每次檢索索引都需要把索引文件加載進(jìn)內(nèi)存悄但,所以磁盤 IO 的次數(shù)是衡量索引數(shù)據(jù)結(jié)構(gòu)好壞的重要指標(biāo)棠隐。應(yīng)用程序在從磁盤讀取數(shù)據(jù)時,不只是讀取需要的數(shù)據(jù)檐嚣,還會連同其他數(shù)據(jù)以頁的形式做預(yù)讀來減少磁盤 IO 的次數(shù)助泽。數(shù)據(jù)庫的設(shè)計者將每個節(jié)點(diǎn)的大小設(shè)置為一頁的大小,同時每次新建節(jié)點(diǎn)時都重新申請一個頁嚎京,這樣檢索一個節(jié)點(diǎn)只需要一次 IO嗡贺,根據(jù)索引定位到數(shù)據(jù)只需要 h- 1(h 為 B 樹高度,根節(jié)點(diǎn)常駐內(nèi)存) 次 IO鞍帝,而 d (度诫睬,可以理解為寬度)與 h 稱反比,即 d 越大帕涌,高度就越小摄凡,所以樹越扁续徽,磁盤 IO 次數(shù)越少,即漸進(jìn)復(fù)雜度為 logdN 架谎,這也是為什么不選擇紅黑樹做索引的原因。前面可以得出結(jié)論辟躏,d 越大谷扣,索引的性能越好。節(jié)點(diǎn)由 key 和 data 組成捎琐,頁的大小一定会涎,key 和 data 越小,d 越大瑞凑。B + 樹去掉了節(jié)點(diǎn)內(nèi)的 data 域末秃,所以有更大的 d , 性能更好。

3籽御、最左前綴原則

在 MySQL 中练慕,可以指定多個列為索引,即聯(lián)合索引技掏。比如 index(name铃将,age) ,最左前綴原則是指查詢時精確匹配到從最左邊開始的一列或幾列(name哑梳;name&age)劲阎,就可以命中索引。如果所有列都用到了鸠真,順序不同悯仙,查詢引擎會自動優(yōu)化為匹配聯(lián)合索引的順序,這樣是能夠命中索引的吠卷。

4锡垄、什么情況下可以用到 B 樹索引

(1) 定義有主鍵的列一定要建立索引。因?yàn)橹麈I可以加速定位到表中的某行

(2) 定義有外鍵的列一定要建立索引祭隔。外鍵列通常用于表與表之間的連接偎捎,在其上創(chuàng)建索引可以加快表間的連接

(3) 對于經(jīng)常查詢的數(shù)據(jù)列最好建立索引。

① 對于需要在指定范圍內(nèi)快速或頻繁查詢的數(shù)據(jù)列序攘,因?yàn)樗饕呀?jīng)排序茴她,其指定的范圍是連續(xù)的,查詢可以利用索引的排序程奠,加快查詢的時間

② 經(jīng)常用在 where 子句中的數(shù)據(jù)列丈牢,將索引建立在 where 子句的集合過程中,對于需要加速或頻繁檢索的數(shù)據(jù)列瞄沙,可以讓這些經(jīng)常參與查詢的數(shù)據(jù)列按照索引的排序進(jìn)行查詢己沛,加快查詢的時間慌核。

5、事務(wù)隔離級別

  • Read uncommitted
    讀未提交申尼,可能出現(xiàn)臟讀垮卓,不可重復(fù)讀,幻讀师幕。
  • Read committed
    讀提交粟按,可能出現(xiàn)不可重復(fù)讀,幻讀霹粥。
  • Repeatable read
    可重復(fù)讀灭将,可能出現(xiàn)臟讀。
  • Serializable
    可串行化后控,同一數(shù)據(jù)讀寫都加鎖庙曙,避免臟讀,性能不忍直視浩淘。

Inno DB 默認(rèn)隔離級別為可重復(fù)讀級別捌朴,分為快照度和當(dāng)前讀,并且通過行鎖和間隙鎖解決了幻讀問題张抄。

6男旗、MVCC (多版本并發(fā)控制)

  • 實(shí)現(xiàn)細(xì)節(jié)
    • 每行數(shù)據(jù)都存在一個版本,每次數(shù)據(jù)更新時都更新該版本欣鳖。
    • 修改時 Copy 出當(dāng)前版本隨意修改察皇,各個事務(wù)之間互不干擾。
    • 保存時比較版本號泽台,如果成功(commit)什荣,則覆蓋原記錄;失敗則放棄 copy(rollback)。
  • Inno DB 實(shí)現(xiàn)

在 InnoDB 中為每行增加兩個隱藏的字段,分別是該行數(shù)據(jù)創(chuàng)建時的版本號刪除時的版本號仰冠,這里的版本號是系統(tǒng)版本號(可以簡單理解為事務(wù)的 ID),每開始一個新的事務(wù)桅锄,系統(tǒng)版本號就自動遞增,作為事務(wù)的 ID 样眠。通常這兩個版本號分別叫做創(chuàng)建時間和刪除時間友瘤。

詳細(xì)參考:《 臟讀、幻讀和不可重復(fù)讀》

六檐束、Spring 相關(guān)

1辫秧、Bean 的作用域

|:---|:---|
| 類別 | 說明 |
|singleton| 默認(rèn)在 Spring 容器中僅存在一個實(shí)例 |
|prototype| 每次調(diào)用 getBean() 都重新生成一個實(shí)例 |
|request| 為每個 HTTP 請求生成一個實(shí)例 |
|session| 同一個 HTTP session 使用一個實(shí)例,不同 session 使用不同實(shí)例 |

2被丧、Bean 生命周期

簡單來說四步:

    1. 實(shí)例化 Instantiation
    1. 屬性賦值 Populate
    1. 初始化 Initialization
    1. 銷毀 Destruction

在這四步的基礎(chǔ)上面盟戏,Spring 提供了一些拓展點(diǎn):

  • Bean 自身的方法: 這個包括了 Bean 本身調(diào)用的方法和通過配置文件中 %3Cbean %3E 的 init-method 和 destroy-method 指定的方法
  • Bean 級生命周期接口方法: 這個包括了 BeanNameAware绪妹、BeanFactoryAware、InitializingBean 和 DiposableBean 這些接口的方法
  • 容器級生命周期接口方法:這個包括了 InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 這兩個接口實(shí)現(xiàn)柿究,一般稱它們的實(shí)現(xiàn)類為“后處理器”邮旷。
  • 工廠后處理器接口方法: 這個包括了 AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer 等等非常有用的工廠后處理器接口的方法。工廠后處理器也是容器級的蝇摸。在應(yīng)用上下文裝配配置文件之后立即調(diào)用婶肩。

3、Spring AOP

實(shí)現(xiàn)方式兩種:

  • JDK 動態(tài)代理:帶有接口的對象探入,在運(yùn)行期實(shí)現(xiàn)
  • CGlib 靜態(tài)代理:在編譯期實(shí)現(xiàn)狡孔。

4懂诗、Spring 事務(wù)傳播行為

默認(rèn) PROPAGATION_REQUIRED 蜂嗽,如果存在一個事務(wù),則支持當(dāng)前事務(wù)殃恒。如果沒有事務(wù)則開啟一個新的事務(wù)植旧。

image.png

5、Spring IoC

image.png

6离唐、Spring MVC 工作流程

七病附、計算機(jī)網(wǎng)絡(luò)

1、TCP/IP 五層模型

image.png

2亥鬓、瀏覽器輸入地址后做了什么完沪?

image.png

3、三次握手與四次揮手

  • 三次握手


    image.png
  • 四次揮手


    image.png

4嵌戈、TIME_WAIT 與 CLOSE_WAIT

image.png

5覆积、TCP 滑動窗口

TCP 流量控制,主要使用滑動窗口協(xié)議熟呛,滑動窗口是接受數(shù)據(jù)端使用的窗口大小宽档,用來告訴發(fā)送端接收端的緩存大小,以此可以控制發(fā)送端發(fā)送數(shù)據(jù)的大小庵朝,從而達(dá)到流量控制的目的吗冤。這個窗口大小就是我們一次傳輸幾個數(shù)據(jù)。對所有數(shù)據(jù)幀按順序賦予編號九府,發(fā)送方在發(fā)送過程中始終保持著一個發(fā)送窗口椎瘟,只有落在發(fā)送窗口內(nèi)的幀才允許被發(fā)送;同時接收方也維持著一個接收窗口侄旬,只有落在接收窗口內(nèi)的幀才允許接收降传。

6、TCP 粘包和拆包

  • 現(xiàn)象


    image.png
  • 產(chǎn)生原因
    1勾怒、要發(fā)送的數(shù)據(jù)大于 TCP 發(fā)送緩沖區(qū)剩余空間大小婆排,將會發(fā)生拆包声旺。
    2、待發(fā)送數(shù)據(jù)大于 MSS(最大報文長度)段只,TCP 在傳輸前將進(jìn)行拆包腮猖。
    3、要發(fā)送的數(shù)據(jù)小于 TCP 發(fā)送緩沖區(qū)的大小赞枕,TCP 將多次寫入緩沖區(qū)的數(shù)據(jù)一次發(fā)送出去澈缺,將會發(fā)生粘包。
    4炕婶、接收數(shù)據(jù)端的應(yīng)用層沒有及時讀取接收緩沖區(qū)中的數(shù)據(jù)姐赡,將發(fā)生粘包。
  • 解決方式
    1柠掂、發(fā)送端給每個數(shù)據(jù)包添加包首部项滑,首部中應(yīng)該至少包含數(shù)據(jù)包的長度,這樣接收端在接收到數(shù)據(jù)后涯贞,通過讀取包首部的長度字段枪狂,便知道每一個數(shù)據(jù)包的實(shí)際長度了。
    2宋渔、發(fā)送端將每個數(shù)據(jù)包封裝為固定長度(不夠的可以通過補(bǔ) 0 填充)州疾,這樣接收端每次從接收緩沖區(qū)中讀取固定長度的數(shù)據(jù)就自然而然的把每個數(shù)據(jù)包拆分開來。
    3皇拣、可以在數(shù)據(jù)包之間設(shè)置邊界严蓖,如添加特殊符號,這樣氧急,接收端通過這個邊界就可以將不同的數(shù)據(jù)包拆分開颗胡。

八、MQ 消息隊(duì)列

1态蒂、場景作用

削峰填谷杭措,異步解耦

2钾恢、如何保證消息不被重復(fù)消費(fèi)呢手素?

這個問題可以換個思路,保證消息重復(fù)消費(fèi)瘩蚪,其實(shí)是保證程序的冪等性泉懦。無論消息如何重復(fù),程序運(yùn)行的結(jié)果是一致的疹瘦。比如消費(fèi)消息后做數(shù)據(jù)庫插入操作崩哩,為了防止消息重復(fù)消費(fèi),可以在插入前先查詢一下有沒有對應(yīng)的數(shù)據(jù)。

3邓嘹、怎么保證從消息隊(duì)列里拿到的數(shù)據(jù)按順序執(zhí)行酣栈?

消費(fèi)端在接收到消息后放入內(nèi)存隊(duì)列,然后對隊(duì)列中的消息進(jìn)行有序消費(fèi)汹押。

4矿筝、如何解決消息隊(duì)列的延時以及過期失效問題?消息隊(duì)列滿了以后該怎么處理棚贾?有幾百萬消息持續(xù)積壓幾小時窖维,說說怎么解決?

消息過期失效問題妙痹,如果消息一段時間不消費(fèi)铸史,導(dǎo)致過期失效了,消息就丟失了怯伊,只能重新查出丟失的消息琳轿,重新發(fā)送。
再來說消息積壓的問題:(思路是快速消費(fèi)掉積壓的消息)

  • 首先排查消費(fèi)端問題震贵,恢復(fù)消費(fèi)端正常消費(fèi)速度利赋。
  • 然后著手處理隊(duì)列中的積壓消息水评。
    • 停掉現(xiàn)有的 consumer猩系。
    • 新建一個 topic ,設(shè)置之前 10 倍的 partation中燥,之前 10 倍的隊(duì)列寇甸。
    • 寫一個分發(fā)程序,將積壓的消息均勻的輪詢寫入這些隊(duì)列疗涉。
    • 然后臨時用 10 倍的機(jī)器部署 consumer拿霉,每一批 consumer 消費(fèi) 1 個臨時的隊(duì)列。
    • 消費(fèi)完畢后咱扣,恢復(fù)原有架構(gòu)绽淘。

消息隊(duì)列滿了:只能邊接收邊丟棄,然后重新補(bǔ)回丟失的消息闹伪,再做消費(fèi)沪铭。

4、如何保證消息的可靠性傳輸(如何處理消息丟失的問題)偏瓤?

kafka 為例:

  • 消費(fèi)者丟了數(shù)據(jù):
    每次消息消費(fèi)后杀怠,由自動提交 offset 改為手動提交 offset 。
  • kafka 丟了消息:
    比較常見的一個場景厅克,就是 kafka 某個 broker 宕機(jī)赔退,然后重新選舉 partition 的 leader 時。要是此時其他的 follower 剛好還有些數(shù)據(jù)沒有同步,結(jié)果此時 leader 掛了硕旗,然后大家選舉某個 follower 成為 leader 之后窗骑,不就少了一些數(shù)據(jù)。
    • 給 topic 設(shè)置replication.factor參數(shù):這個值必須大于 1漆枚,要求每個 partition 必須有至少兩個副本慧域。
    • 在 kafka 服務(wù)端設(shè)置min.insync.replicas參數(shù):這個值必須大于 1,這個是要求一個 leader 至少感知到有至少一個 follower 還跟自己保持聯(lián)系浪读,沒掉隊(duì)昔榴,這樣才能確保 leader 掛了還有一個 follower。
    • 在 producer 端設(shè)置acks=all:這個是要求每條數(shù)據(jù)碘橘,必須是寫入所有 replica 之后互订,才能認(rèn)為是寫成功了。
    • 在 producer 端設(shè)置retries=MAX(很大很大很大的一個值痘拆,無限次重試的意思):這個是要求一旦寫入失敗仰禽,就無限重試,卡在這里纺蛆。
  • 生產(chǎn)者丟了消息:
    如果按照上述的思路設(shè)置了 ack=all吐葵,一定不會丟,要求是桥氏,你的 leader 接收到消息温峭,所有的 follower 都同步到了消息之后,才認(rèn)為本次寫成功了字支。如果沒滿足這個條件凤藏,生產(chǎn)者會自動不斷的重試,重試無限次堕伪。

九揖庄、Redis

1、數(shù)據(jù)類型

  • String

常用命令: set,get,decr,incr,mget 等欠雌。

  • Hash

常用命令: hget,hset,hgetall 等

  • List

常用命令: lpush,rpush,lpop,rpop,lrange 等

可以通過 lrange 命令蹄梢,就是從某個元素開始讀取多少個元素,可以基于 list 實(shí)現(xiàn)分頁查詢富俄。

  • Set

常用命令: sadd,spop,smembers,sunion 等

  • Sort Set

常用命令: zadd,zrange,zrem,zcard 等

2禁炒、Redis 如何實(shí)現(xiàn) key 的過期刪除?

定期刪除和惰性刪除的形式蛙酪。

  • 定期刪除
    Redis 每隔一段時間從設(shè)置過期時間的 key 集合中齐苛,隨機(jī)抽取一些 key ,檢查是否過期桂塞,如果已經(jīng)過期做刪除處理凹蜂。
  • 惰性刪除
    Redis 在 key 被訪問的時候檢查 key 是否過期,如果過期則刪除。

3玛痊、Redis 的持久化機(jī)制

數(shù)據(jù)快照(RDB)+ 修改數(shù)據(jù)語句文件(AOF)

4汰瘫、如何解決 Redis 緩存雪崩和緩存穿透?

  • 緩存雪崩
    緩存同一時間大面積的失效擂煞,所以混弥,后面的請求都會落到數(shù)據(jù)庫上,造成數(shù)據(jù)庫短時間內(nèi)承受大量請求而崩掉对省。

    • 解決方式
      • 事前:保證 Redis 集群的穩(wěn)定性蝗拿,發(fā)現(xiàn)機(jī)器宕機(jī)盡快補(bǔ)上,設(shè)置合適的內(nèi)存淘汰策略蒿涎。
      • 事中:本地緩存 + 限流降級哀托,避免大量請求落在數(shù)據(jù)庫上。
      • 事后:利用 Redis 持久化機(jī)制盡快恢復(fù)緩存劳秋。
  • 緩存穿透
    一般是黑客故意去請求緩存中不存在的數(shù)據(jù)仓手,導(dǎo)致所有的請求都落到數(shù)據(jù)庫上,造成數(shù)據(jù)庫短時間內(nèi)承受大量請求而崩掉玻淑。

    • 解決方式
      將不存在的數(shù)據(jù)列舉到一個足夠大的 map 上嗽冒,這樣遭到攻擊時,直接攔截 map 中的請求补履,請求到數(shù)據(jù)庫上面添坊。或是把不存在的也做緩存干像,值為 null 帅腌,設(shè)置過期時間驰弄。

5麻汰、如何使用 Redis 實(shí)現(xiàn)消息隊(duì)列?

Redis 實(shí)現(xiàn)消息隊(duì)列依賴于 Redis 集群的穩(wěn)定性戚篙,通常不建議使用五鲫。

  • Redis 自帶發(fā)布訂閱功能,基于 publish 和 subscribe 命令岔擂。
  • 使用 List 存儲消息位喂,lpush,rpop 分別發(fā)送接收消息乱灵。

十塑崖、Nginx

Nginx 是一款輕量級的 Web 服務(wù)器/反向代理服務(wù)器及電子郵件(IMAP/POP3)代理服務(wù)器。 Nginx 主要提供反向代
理痛倚、負(fù)載均衡规婆、動靜分離(靜態(tài)資源服務(wù))等服務(wù)。

1、正向代理和反向代理

  • 正向代理
    代理客戶端訪問服務(wù)器抒蚜。典型:VPN
  • 反向代理
    代替服務(wù)器接收客戶端請求掘鄙,然后轉(zhuǎn)發(fā)給服務(wù)器,服務(wù)器接收請求并將處理的結(jié)果通過代理服務(wù)器轉(zhuǎn)發(fā)給客戶端嗡髓。

2操漠、負(fù)載均衡

將請求分?jǐn)偟蕉嗯_機(jī)器上去,高并發(fā)饿这,增加吞吐量浊伙。

  • 負(fù)載均衡算法
    • 權(quán)重輪詢
    • fair
    • ip_hash
    • url_hash

3、動靜分離

動靜分離是讓動態(tài)網(wǎng)站里的動態(tài)網(wǎng)頁根據(jù)一定規(guī)則把不變的資源和經(jīng)常變的資源區(qū)分開來长捧,動靜資源做好了拆分以后吧黄,我們就可以根據(jù)靜態(tài)資源的特點(diǎn)將其做緩存操作,這就是網(wǎng)站靜態(tài)化處理的核心思路唆姐。

4拗慨、Nginx 四個組成部分

  • Nginx 二進(jìn)制可執(zhí)行文件:由各模塊源碼編譯出一個文件
  • Nginx.conf 配置文件:控制 Nginx 行為
  • acess.log 訪問日志: 記錄每一條 HTTP 請求信息
  • error.log 錯誤日志:定位問題

歡迎訪問個人博客 獲取更多知識分享。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奉芦,一起剝皮案震驚了整個濱河市赵抢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌声功,老刑警劉巖烦却,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異先巴,居然都是意外死亡其爵,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門伸蚯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來摩渺,“玉大人,你說我怎么就攤上這事剂邮∫』茫” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵挥萌,是天一觀的道長绰姻。 經(jīng)常有香客問我,道長引瀑,這世上最難降的妖魔是什么狂芋? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮憨栽,結(jié)果婚禮上帜矾,老公的妹妹穿的比我還像新娘辆影。我一直安慰自己,他們只是感情好黍特,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布蛙讥。 她就那樣靜靜地躺著,像睡著了一般灭衷。 火紅的嫁衣襯著肌膚如雪次慢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天翔曲,我揣著相機(jī)與錄音迫像,去河邊找鬼。 笑死瞳遍,一個胖子當(dāng)著我的面吹牛闻妓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播掠械,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼由缆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了猾蒂?” 一聲冷哼從身側(cè)響起均唉,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肚菠,沒想到半個月后舔箭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚊逢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年层扶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烙荷。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡镜会,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出奢讨,到底是詐尸還是另有隱情稚叹,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布拿诸,位于F島的核電站,受9級特大地震影響塞茅,放射性物質(zhì)發(fā)生泄漏亩码。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一野瘦、第九天 我趴在偏房一處隱蔽的房頂上張望描沟。 院中可真熱鬧飒泻,春花似錦、人聲如沸吏廉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽席覆。三九已至史辙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間佩伤,已是汗流浹背聊倔。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留生巡,地道東北人耙蔑。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像孤荣,于是被迫代替她去往敵國和親甸陌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355