Android 面試之 Java 篇三

本文出自 Eddy Wiki 嗜历,轉(zhuǎn)載請注明出處:http://eddy.wiki/interview-java.html

本文收集整理了 Android 面試中會遇到與 Java 知識相關(guān)的簡述題。

多線程

一個線程的生命周期

線程是一個動態(tài)執(zhí)行的過程,它也有一個從產(chǎn)生到死亡的過程闻丑。

下圖顯示了一個線程完整的生命周期挠锥。

img
  • 新建狀態(tài):使用 new 關(guān)鍵字和 Thread 類或其子類建立一個線程對象后众羡,該線程對象就處于新建狀態(tài)。它保持這個狀態(tài)直到程序 start() 這個線程蓖租。
  • 就緒狀態(tài):當(dāng)線程對象調(diào)用了start()方法之后粱侣,該線程就進入就緒狀態(tài)羊壹。就緒狀態(tài)的線程處于就緒隊列中,要等待JVM里線程調(diào)度器的調(diào)度齐婴。
  • 運行狀態(tài):如果就緒狀態(tài)的線程獲取 CPU 資源油猫,就可以執(zhí)行 run(),此時線程便處于運行狀態(tài)柠偶。處于運行狀態(tài)的線程最為復(fù)雜情妖,它可以變?yōu)樽枞麪顟B(tài)、就緒狀態(tài)和死亡狀態(tài)诱担。
  • 阻塞狀態(tài):如果一個線程執(zhí)行了sleep(睡眠)毡证、suspend(掛起)等方法,失去所占用資源之后蔫仙,該線程就從運行狀態(tài)進入阻塞狀態(tài)料睛。在睡眠時間已到或獲得設(shè)備資源后可以重新進入就緒狀態(tài)∫“睿可以分為三種: 等待阻塞:運行狀態(tài)中的線程執(zhí)行 wait() 方法恤煞,使線程進入到等待阻塞狀態(tài)。同步阻塞:線程在獲取 synchronized 同步鎖失敗(因為同步鎖被其他線程占用)施籍。其他阻塞:通過調(diào)用線程的 sleep() 或 join() 發(fā)出了 I/O 請求時居扒,線程就會進入到阻塞狀態(tài)。當(dāng)sleep() 狀態(tài)超時法梯,join() 等待線程終止或超時苔货,或者 I/O 處理完畢,線程重新轉(zhuǎn)入就緒狀態(tài)立哑。
  • **死亡狀態(tài): **一個運行狀態(tài)的線程完成任務(wù)或者其他終止條件發(fā)生時夜惭,該線程就切換到終止?fàn)顟B(tài)。

Java 線程幾種用法

進程和線程的區(qū)別

程序是一段靜態(tài)的代碼铛绰。一個進程可以有一個或多個線程诈茧,每個線程都有一個唯一的標(biāo)識符。

進程和線程的區(qū)別為:進程空間大體分為數(shù)據(jù)區(qū)捂掰、代碼區(qū)敢会、棧區(qū)、堆區(qū)这嚣。多個進程的內(nèi)部數(shù)據(jù)和狀態(tài)都是完全獨立的鸥昏;而線程共享進程的數(shù)據(jù)區(qū)、代碼區(qū)姐帚、堆區(qū)吏垮,只有棧區(qū)是獨立的,所以線程切換比進程切換的代價小。

多線程技術(shù)是使得單個程序內(nèi)部可以在同一時刻執(zhí)行多個代碼段膳汪,完成不同的任務(wù)唯蝶,這種機制稱為多線程。同時并不是指真正意義上的同一時刻遗嗽,而是指多個線程輪流占用CPU的時間片粘我。


簡而言之,一個程序至少有一個進程痹换,一個進程至少有一個線程征字。

線程的劃分尺度小于進程,使得多線程程序的并發(fā)性高娇豫。

另外柔纵,進程在執(zhí)行過程中擁有獨立的內(nèi)存單元,而多個線程共享內(nèi)存锤躁,從而極大地提高了程序的運行效率。

線程在執(zhí)行過程中與進程還是有區(qū)別的或详。每個獨立的線程有一個程序運行的入口系羞、順序執(zhí)行序列和程序的出口。但是線程不能夠獨立執(zhí)行霸琴,必須依存在應(yīng)用程序中椒振,由應(yīng)用程序提供多個線程執(zhí)行控制。

從邏輯角度來看梧乘,多線程的意義在于一個應(yīng)用程序中澎迎,有多個執(zhí)行部分可以同時執(zhí)行。但操作系統(tǒng)并沒有將多個線程看做多個獨立的應(yīng)用选调,來實現(xiàn)進程的調(diào)度和管理以及資源分配夹供。這就是進程和線程的重要區(qū)別。

進程是具有一定獨立功能的程序關(guān)于某個數(shù)據(jù)集合上的一次運行活動,進程是系統(tǒng)進行資源分配和調(diào)度的一個獨立單位.

線程是進程的一個實體,是CPU調(diào)度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源(如程序計數(shù)器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.

一個線程可以創(chuàng)建和撤銷另一個線程;同一個進程中的多個線程之間可以并發(fā)執(zhí)行.

進程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式仁堪。進程有獨立的地址空間哮洽,一個進程崩潰后,在保護模式下不會對其它進程產(chǎn)生影響弦聂,而線程只是一個進程中的不同執(zhí)行路徑鸟辅。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間莺葫,一個線程死掉就等于整個進程死掉匪凉,所以多進程的程序要比多線程的程序健壯,但在進程切換時捺檬,耗費資源較大再层,效率要差一些。但對于一些要求同時進行并且又要共享某些變量的并發(fā)操作,只能用線程树绩,不能用進程萨脑。

什么會導(dǎo)致線程阻塞

線程被堵塞可能是由下述五方面的原因造成的:

  1. 調(diào)用sleep(毫秒數(shù)),使線程進入“睡眠”狀態(tài)饺饭。在規(guī)定的時間內(nèi)渤早,這個線程是不會運行的。
  2. 用suspend()暫停了線程的執(zhí)行瘫俊。除非線程收到resume()消息鹊杖,否則不會返回“可運行”狀態(tài)。
  3. 用wait()暫停了線程的執(zhí)行扛芽。除非線程收到nofify()或者notifyAll()消息骂蓖,否則不會變成“可運行”。
  4. 線程正在等候一些IO(輸入輸出)操作完成川尖。
  5. 線程試圖調(diào)用另一個對象的“同步”方法登下,但那個對象處于鎖定狀態(tài),暫時無法使用叮喳。

啟動一個線程是用run()還是start()?

啟動一個線程是調(diào)用start()方法被芳,使線程就緒狀態(tài),以后可以被調(diào)度為運行狀態(tài)馍悟,一個線程必須關(guān)聯(lián)一些具體的執(zhí)行代碼畔濒,run()方法是該線程所關(guān)聯(lián)的執(zhí)行代碼。

多線程有幾種實現(xiàn)方法,都是什么?

Java 提供了三種創(chuàng)建線程的方法:

  • 通過實現(xiàn) Runable 接口锣咒;
  • 通過繼承 Thread類本身侵状;
  • 通過 Callable 和 Future 創(chuàng)建線程。

多線程有兩種實現(xiàn)方法毅整,分別是繼承Thread類與實現(xiàn)Runnable接口趣兄。

Java 5以前實現(xiàn)多線程有兩種實現(xiàn)方法:一種是繼承Thread類;另一種是實現(xiàn)Runnable接口悼嫉。兩種方式都要通過重寫run()方法來定義線程的行為诽俯,推薦使用后者,因為Java中的繼承是單繼承承粤,一個類有一個父類暴区,如果繼承了Thread類就無法再繼承其他類了,顯然使用Runnable接口更為靈活。

實現(xiàn)Runnable接口相比繼承Thread類有如下優(yōu)勢:

  1. 可以避免由于Java的單繼承特性而帶來的局限
  2. 增強程序的健壯性,代碼能夠被多個程序共享悦冀,代碼與數(shù)據(jù)是獨立的
  3. 適合多個相同程序代碼的線程區(qū)處理同一資源的情況

補充:Java 5以后創(chuàng)建線程還有第三種方式:實現(xiàn)Callable接口蚓哩,該接口中的call方法可以在線程執(zhí)行結(jié)束時產(chǎn)生一個返回值,代碼如下所示:

class MyTask implements Callable<Integer> {  
    private int upperBounds;  

    public MyTask(int upperBounds) {  
        this.upperBounds = upperBounds;  
    }  

    @Override  
    public Integer call() throws Exception {  
        int sum = 0;   
        for(int i = 1; i <= upperBounds; i++) {  
            sum += i;  
        }  
        return sum;  
    }  

}  

public class Test {  

    public static void main(String[] args) throws Exception {  
        List<Future<Integer>> list = new ArrayList<>();  
        ExecutorService service = Executors.newFixedThreadPool(10);  
        for(int i = 0; i < 10; i++) {  
            list.add(service.submit(new MyTask((int) (Math.random() * 100))));  
        }  

        int sum = 0;  
        for(Future<Integer> future : list) {  
            while(!future.isDone()) ;  
            sum += future.get();  
        }  

        System.out.println(sum);  
    }  
}  

同步有幾種實現(xiàn)方法,都是什么?

同步的實現(xiàn)方面有兩種妥箕,分別是synchronized抒寂、wait與notify

鎖的等級

方法鎖洪灯、對象鎖隔心、類鎖

同步和異步的區(qū)別白群?

同步:A線程要請求某個資源,但是此資源正在被B線程使用中硬霍,因為同步機制存在帜慢,A線程請求不到,怎么辦唯卖,A線程只能等待下去

異步:A線程要請求某個資源粱玲,但是此資源正在被B線程使用中,因為沒有同步機制存在拜轨,A線程仍然請求的到抽减,A線程無需等待


在進行網(wǎng)絡(luò)編程時,我們通常會看到同步橄碾、異步卵沉、阻塞、非阻塞四種調(diào)用方式以及他們的組合法牲。

其中同步方式偎箫、異步方式主要是由客戶端(client)控制的,具體如下:

同步(Sync)

所謂同步皆串,就是發(fā)出一個功能調(diào)用時,在沒有得到結(jié)果之前眉枕,該調(diào)用就不返回或繼續(xù)執(zhí)行后續(xù)操作恶复。

異步(Async)

異步與同步相對,當(dāng)一個異步過程調(diào)用發(fā)出后速挑,調(diào)用者在沒有得到結(jié)果之前谤牡,就可以繼續(xù)執(zhí)行后續(xù)操作。當(dāng)這個調(diào)用完成后姥宝,一般通過狀態(tài)翅萤、通知和回調(diào)來通知調(diào)用者。對于異步調(diào)用腊满,調(diào)用的返回并不受調(diào)用者控制套么。

sleep和wait有什么區(qū)別?

一個是用來讓線程休息碳蛋,一個是用來掛起線程

  • 對于sleep()方法胚泌,我們首先要知道該方法是屬于Thread類中的。而wait()方法肃弟,則是屬于Object類中的玷室。
  • sleep():正在執(zhí)行的線程主動讓出CPU(然后CPU就可以去執(zhí)行其他任務(wù))零蓉,在sleep指定時間后CPU再回到該線程繼續(xù)往下執(zhí)行。注意:sleep方法只讓出了CPU穷缤,而并不會釋放同步資源鎖敌蜂!

wait():則是指當(dāng)前線程讓自己暫時退讓出同步資源鎖,以便其他正在等待該資源的線程得到該資源進而運行津肛,只有調(diào)用了notify()方法章喉,之前調(diào)用wait()的線程才會解除wait狀態(tài),可以去參與競爭同步資源鎖快耿,進而得到執(zhí)行

sleep()方法是線程類(Thread)的靜態(tài)方法囊陡,導(dǎo)致此線程暫停執(zhí)行指定時間,將執(zhí)行機會給其他線程掀亥,但是監(jiān)控狀態(tài)依然保持撞反,到時后會自動恢復(fù)(線程回到就緒(ready)狀態(tài)),因為調(diào)用sleep 不會釋放對象鎖搪花。

wait()是Object 類的方法遏片,對此對象調(diào)用wait()方法導(dǎo)致本線程放棄對象鎖(線程暫停執(zhí)行),進入等待此對象的等待鎖定池撮竿,只有針對此對象發(fā)出notify 方法(或notifyAll)后本線程才進入對象鎖定池準(zhǔn)備獲得對象鎖進入就緒狀態(tài)吮便。

Java線程池,線程同步

詳細講解一下 synchronized

在并發(fā)編程中幢踏,多線程同時并發(fā)訪問的資源叫做臨界資源髓需,當(dāng)多個線程同時訪問對象并要求操作相同資源時,分割了原子操作就有可能出現(xiàn)數(shù)據(jù)的不一致或數(shù)據(jù)不完整的情況房蝉,為避免這種情況的發(fā)生僚匆,我們會采取同步機制,以確保在某一時刻搭幻,方法內(nèi)只允許有一個線程咧擂。

采用synchronized修飾符實現(xiàn)的同步機制叫做互斥鎖機制,它所獲得的鎖叫做互斥鎖檀蹋。每個對象都有一個monitor(鎖標(biāo)記)松申,當(dāng)線程擁有這個鎖標(biāo)記時才能訪問這個資源,沒有鎖標(biāo)記便進入鎖池俯逾。任何一個對象系統(tǒng)都會為其創(chuàng)建一個互斥鎖贸桶,這個鎖是為了分配給線程的,防止打斷原子操作桌肴。每個對象的鎖只能分配給一個線程刨啸,因此叫做互斥鎖。

這里就使用同步機制獲取互斥鎖的情況识脆,進行幾點說明:

  1. 如果同一個方法內(nèi)同時有兩個或更多線程设联,則每個線程有自己的局部變量拷貝善已。
  2. 類的每個實例都有自己的對象級別鎖。當(dāng)一個線程訪問實例對象中的synchronized同步代碼塊或同步方法時离例,該線程便獲取了該實例的對象級別鎖换团,其他線程這時如果要訪問synchronized同步代碼塊或同步方法,便需要阻塞等待宫蛆,直到前面的線程從同步代碼塊或方法中退出艘包,釋放掉了該對象級別鎖。
  3. 訪問同一個類的不同實例對象中的同步代碼塊想虎,不存在阻塞等待獲取對象鎖的問題,因為它們獲取的是各自實例的對象級別鎖裙椭,相互之間沒有影響筋栋。
  4. 持有一個對象級別鎖不會阻止該線程被交換出來抢腐,也不會阻塞其他線程訪問同一示例對象中的非synchronized代碼婿着。當(dāng)一個線程A持有一個對象級別鎖(即進入了synchronized修飾的代碼塊或方法中)時竟宋,線程也有可能被交換出去丘侠,此時線程B有可能獲取執(zhí)行該對象中代碼的時間打肝,但它只能執(zhí)行非同步代碼(沒有用synchronized修飾)级零,當(dāng)執(zhí)行到同步代碼時鉴嗤,便會被阻塞炕置,此時可能線程規(guī)劃器又讓A線程運行默垄,A線程繼續(xù)持有對象級別鎖甚纲,當(dāng)A線程退出同步代碼時(即釋放了對象級別鎖),如果B線程此時再運行介杆,便會獲得該對象級別鎖,從而執(zhí)行synchronized中的代碼春哨。
  5. 持有對象級別鎖的線程會讓其他線程阻塞在所有的synchronized代碼外。例如赴背,在一個類中有三個synchronized方法a,b燃观,c脊框,當(dāng)線程A正在執(zhí)行一個實例對象M中的方法a時适篙,它便獲得了該對象級別鎖,那么其他的線程在執(zhí)行同一實例對象(即對象M)中的代碼時箫爷,便會在所有的synchronized方法處阻塞嚷节,即在方法a,b虎锚,c處都要被阻塞硫痰,等線程A釋放掉對象級別鎖時,其他的線程才可以去執(zhí)行方法a窜护,b或者c中的代碼效斑,從而獲得該對象級別鎖。
  6. 使用synchronized(obj)同步語句塊柱徙,可以獲取指定對象上的對象級別鎖缓屠。obj為對象的引用,如果獲取了obj對象上的對象級別鎖护侮,在并發(fā)訪問obj對象時時敌完,便會在其synchronized代碼處阻塞等待,直到獲取到該obj對象的對象級別鎖羊初。當(dāng)obj為this時滨溉,便是獲取當(dāng)前對象的對象級別鎖。
  7. 類級別鎖被特定類的所有示例共享长赞,它用于控制對static成員變量以及static方法的并發(fā)訪問晦攒。具體用法與對象級別鎖相似。
  8. 互斥是實現(xiàn)同步的一種手段得哆,臨界區(qū)脯颜、互斥量和信號量都是主要的互斥實現(xiàn)方式。synchronized關(guān)鍵字經(jīng)過編譯后贩据,會在同步塊的前后分別形成monitorenter和monitorexit這兩個字節(jié)碼指令栋操。根據(jù)虛擬機規(guī)范的要求,在執(zhí)行monitorenter指令時乐设,首先要嘗試獲取對象的鎖讼庇,如果獲得了鎖绎巨,把鎖的計數(shù)器加1近尚,相應(yīng)地,在執(zhí)行monitorexit指令時會將鎖計數(shù)器減1场勤,當(dāng)計數(shù)器為0時戈锻,鎖便被釋放了歼跟。由于synchronized同步塊對同一個線程是可重入的,因此一個線程可以多次獲得同一個對象的互斥鎖格遭,同樣哈街,要釋放相應(yīng)次數(shù)的該互斥鎖,才能最終釋放掉該鎖拒迅。

當(dāng)一個線程進入一個對象的一個synchronized方法后骚秦,其它線程是否可進入此對象的其它方法?

  • 可以調(diào)用此對象的其他非 synchronized 方法;
  • 可以調(diào)用此對象的 synchronized static 方法璧微;
public class A {
     
    /**
     * 靜態(tài)方法
     */
    public synchronized static void staticMethod(){}
     
    /**
     * 實例方法
     */
    public synchronized void instanceMethod(){}
    public static void main(String[] args) {
         
        //A實例的創(chuàng)建過程
        Class c = Class.forName("A");
        A a1 = c.newInstance();
        A a2 = c.newInstance();
        A a3 = c.newInstance();
    }
}

如上代碼所示作箍,你看一看main方法里面A實例的創(chuàng)建過程,這個要先理解staticMethod這個靜態(tài)方法前硫,無法你實例化多少次胞得,它都只是存在一個,就像Class c指向的對象屹电,它在jvm中也只會存在一個阶剑,staticMethod方法鎖住的是c指向的實例。

instanceMethod這個實例方法危号,你創(chuàng)建多少個A實例牧愁,這些實例都存在各自的instanceMethod方法,這個方法前加synchronized關(guān)鍵詞葱色,會鎖住該instanceMethod方法所在的實例递宅。如a1的instanceMethod方法會鎖住a1指向的實例,a2的instanceMethod會鎖住a2指向的實例苍狰。

由此得出結(jié)論办龄,staticMethod與instanceMethod鎖住的對象是不可能相同的,這就是兩個方法不能同步的原因淋昭。

內(nèi)存可見性

加鎖(synchronized同步)的功能不僅僅局限于互斥行為俐填,同時還存在另外一個重要的方面:內(nèi)存可見性。我們不僅希望防止某個線程正在使用對象狀態(tài)而另一個線程在同時修改該狀態(tài)翔忽,而且還希望確保當(dāng)一個線程修改了對象狀態(tài)后英融,其他線程能夠看到該變化。而線程的同步恰恰也能夠?qū)崿F(xiàn)這一點歇式。

內(nèi)置鎖可以用于確保某個線程以一種可預(yù)測的方式來查看另一個線程的執(zhí)行結(jié)果驶悟。為了確保所有的線程都能看到共享變量的最新值,可以在所有執(zhí)行讀操作或?qū)懖僮鞯木€程上加上同一把鎖材失。下圖示例了同步的可見性保證痕鳍。

當(dāng)線程A執(zhí)行某個同步代碼塊時,線程B隨后進入由同一個鎖保護的同步代碼塊,這種情況下可以保證笼呆,當(dāng)鎖被釋放前熊响,A看到的所有變量值(鎖釋放前,A看到的變量包括y和x)在B獲得同一個鎖后同樣可以由B看到诗赌。換句話說汗茄,當(dāng)線程B執(zhí)行由鎖保護的同步代碼塊時,可以看到線程A之前在同一個鎖保護的同步代碼塊中的所有操作結(jié)果铭若。如果在線程A unlock M之后洪碳,線程B才進入lock M,那么線程B都可以看到線程A unlock M之前的操作叼屠,可以得到i=1偶宫,j=1。如果在線程B unlock M之后环鲤,線程A才進入lock M纯趋,那么線程B就不一定能看到線程A中的操作,因此j的值就不一定是1冷离。

現(xiàn)在考慮如下代碼:

public class  MutableInteger  
{  
    private int value;  

    public int get(){  
        return value;  
    }  
    public void set(int value){  
        this.value = value;  
    }  
}  

以上代碼中吵冒,get和set方法都在沒有同步的情況下訪問value。如果value被多個線程共享西剥,假如某個線程調(diào)用了set痹栖,那么另一個正在調(diào)用get的線程可能會看到更新后的value值,也可能看不到瞭空。

通過對set和get方法進行同步揪阿,可以使MutableInteger成為一個線程安全的類,如下:

public class  SynchronizedInteger  
{  
    private int value;  

    public synchronized int get(){  
        return value;  
    }  
    public synchronized void set(int value){  
        this.value = value;  
    }  
}  

對set和get方法進行了同步咆畏,加上了同一把對象鎖南捂,這樣get方法可以看到set方法中value值的變化,從而每次通過get方法取得的value的值都是最新的value值旧找。

Atomic溺健、volatile、synchronized區(qū)別

面Java基礎(chǔ)的時候遇上了這個問題钮蛛,說如果只有一個i++;的時候鞭缭,volatilesynchronized能否互換。當(dāng)時也不知道魏颓,感覺volatile作為修飾變量的時候岭辣,變量自加會出現(xiàn)加到一半發(fā)生線程調(diào)度。再看看當(dāng)時蒙對了甸饱。

volatile
可以保證在一個線程的工作內(nèi)存中修改了該變量的值沦童,該變量的值立即能回顯到主內(nèi)存中,從而保證所有的線程看到這個變量的值是一致的。但是有個前提搞动,因為它
不具有操作的原子性,也就是它不適合在對該變量的寫操作依賴于變量本身自己渣刷。就比如i++鹦肿、i+=1;這種。但是可以改為num=i+1;如果i是一個 volatile 類型辅柴,那么num就是安全的箩溃,總之就是不能作用于自身。

synchronized是基于代碼塊的碌嘀,只要包含在synchronized塊中涣旨,就是線程安全的。

既然都說了線程安全股冗,就多了解幾個:

AtomicInteger,一個輕量級的synchronized。使用的并不是同步代碼塊矫俺,而是Lock-Free算法(我也不懂阳仔,看代碼就是一個死循環(huán)調(diào)用了底層的比較方法直到相同后才退出循環(huán))。最終的結(jié)果就是在高并發(fā)的時候怯疤,或者說競爭激烈的時候效率比synchronized高一些浆洗。

ThreadLocal,線程中私有數(shù)據(jù)集峦。主要用于線程改變內(nèi)部的數(shù)據(jù)時不影響其他線程伏社,使用時需要注意static

詳細分析見這篇文章 塔淤。

再補一個摘昌,才學(xué)到的。利用clone()方法高蜂,如果是一個類的多個對象想共用對象內(nèi)部的一個變量第焰,而又不想這個變量static,可以使用淺復(fù)制方式妨马。(查看設(shè)計模式原型模式)

并發(fā)編程中實現(xiàn)內(nèi)存可見的兩種方法比較:加鎖和volatile變量

  1. volatile變量是一種稍弱的同步機制在訪問volatile變量時不會執(zhí)行加鎖操作挺举,因此也就不會使執(zhí)行線程阻塞,因此volatile變量是一種比synchronized關(guān)鍵字更輕量級的同步機制烘跺。
  1. 從內(nèi)存可見性的角度看湘纵,寫入volatile變量相當(dāng)于退出同步代碼塊,而讀取volatile變量相當(dāng)于進入同步代碼塊滤淳。
  2. 在代碼中如果過度依賴volatile變量來控制狀態(tài)的可見性梧喷,通常會比使用鎖的代碼更脆弱,也更難以理解。僅當(dāng)volatile變量能簡化代碼的實現(xiàn)以及對同步策略的驗證時铺敌,才應(yīng)該使用它汇歹。一般來說,用同步機制會更安全些偿凭。
  3. 加鎖機制(即同步機制)既可以確辈可見性又可以確保原子性,而volatile變量只能確蓖淠遥可見性痰哨,原因是聲明為volatile的簡單變量如果當(dāng)前值與該變量以前的值相關(guān),那么volatile關(guān)鍵字不起作用匾嘱,也就是說如下的表達式都不是原子操作:“count++”斤斧、“count = count+1”。

當(dāng)且僅當(dāng)滿足以下所有條件時霎烙,才應(yīng)該使用volatile變量:

  1. 對變量的寫入操作不依賴變量的當(dāng)前值撬讽,或者你能確保只有單個線程更新變量的值。
  2. 該變量沒有包含在具有其他變量的不變式中悬垃。

總結(jié):在需要同步的時候锐秦,第一選擇應(yīng)該是synchronized關(guān)鍵字,這是最安全的方式盗忱,嘗試其他任何方式都是有風(fēng)險的酱床。尤其在、jdK1.5之后趟佃,對synchronized同步機制做了很多優(yōu)化扇谣,如:自適應(yīng)的自旋鎖、鎖粗化闲昭、鎖消除罐寨、輕量級鎖等,使得它的性能明顯有了很大的提升序矩。

用wait/notify來實現(xiàn)最簡單的生產(chǎn)者-消費者模式

生產(chǎn)者和消費者問題

守護線程與阻塞線程的四種情況

Java中有兩類線程:User Thread(用戶線程)鸯绿、Daemon Thread(守護線程)

用戶線程即運行在前臺的線程,而守護線程是運行在后臺的線程簸淀。 守護線程作用是為其他前臺線程的運行提供便利服務(wù)瓶蝴,而且僅在普通、非守護線程仍然運行時才需要租幕,比如垃圾回收線程就是一個守護線程舷手。當(dāng)VM檢測僅剩一個守護線程,而用戶線程都已經(jīng)退出運行時劲绪,VM就會退出男窟,因為如果沒有了守護者盆赤,也就沒有繼續(xù)運行程序的必要了。如果有非守護線程仍然活著歉眷,VM就不會退出牺六。

守護線程并非只有虛擬機內(nèi)部提供,用戶在編寫程序時也可以自己設(shè)置守護線程汗捡。用戶可以用Thread的setDaemon(true)方法設(shè)置當(dāng)前線程為守護線程淑际。

雖然守護線程可能非常有用,但必須小心確保其它所有非守護線程消亡時凉唐,不會由于它的終止而產(chǎn)生任何危害。因為你不可能知道在所有的用戶線程退出運行前霍骄,守護線程是否已經(jīng)完成了預(yù)期的服務(wù)任務(wù)台囱。一旦所有的用戶線程退出了,虛擬機也就退出運行了读整。因此簿训,不要再守護線程中執(zhí)行業(yè)務(wù)邏輯操作(比如對數(shù)據(jù)的讀寫等)。

還有幾點:

  1. setDaemon(true)必須在調(diào)用線程的start()方法之前設(shè)置米间,否則會跑出IllegalThreadStateException異常强品。
  2. 在守護線程中產(chǎn)生的新線程也是守護線程
  3. 不要認(rèn)為所有的應(yīng)用都可以分配給守護線程來進行服務(wù),比如讀寫操作或者計算邏輯屈糊。

死鎖

當(dāng)線程需要同時持有多個鎖時的榛,有可能產(chǎn)生死鎖÷呷瘢考慮如下情形:

線程A當(dāng)前持有互斥所鎖lock1夫晌,線程B當(dāng)前持有互斥鎖lock2。接下來昧诱,當(dāng)線程A仍然持有l(wèi)ock1時晓淀,它試圖獲取lock2,因為線程B正持有l(wèi)ock2盏档,因此線程A會阻塞等待線程B對lock2的釋放凶掰。如果此時線程B在持有l(wèi)ock2的時候,也在試圖獲取lock1蜈亩,因為線程A正持有l(wèi)ock1懦窘,因此線程B會阻塞等待A對lock1的釋放。二者都在等待對方所持有鎖的釋放稚配,而二者卻又都沒釋放自己所持有的鎖奶赠,這時二者便會一直阻塞下去。這種情形稱為死鎖药有。

下面給出一個兩個線程間產(chǎn)生死鎖的示例毅戈,如下:

public class Deadlock {

    private String objID;

    public Deadlock(String id) {
        objID = id;
    }

    public synchronized void checkOther(Deadlock other) {
        print("entering checkOther()");  
        try { Thread.sleep(2000); }   
        catch ( InterruptedException x ) { }  
        print("in checkOther() - about to " + "invoke 'other.action()'");  
      //調(diào)用other對象的action方法苹丸,由于該方法是同步方法,因此會試圖獲取other對象的對象鎖  
        other.action();  
        print("leaving checkOther()");  
    }

    public synchronized void action() {  
        print("entering action()");  
        try { Thread.sleep(500); }   
        catch ( InterruptedException x ) { }  
        print("leaving action()");  
    }  

    public void print(String msg) {
        threadPrint("objID=" + objID + " - " + msg);
    }

    public static void threadPrint(String msg) {  
        String threadName = Thread.currentThread().getName();  
        System.out.println(threadName + ": " + msg);  
    }  

    public static void main(String[] args) {
        final Deadlock obj1 = new Deadlock("obj1");  
        final Deadlock obj2 = new Deadlock("obj2");  

        Runnable runA = new Runnable() {  
            public void run() {  
                obj1.checkOther(obj2);  
            }  
        };  

        Thread threadA = new Thread(runA, "threadA");  
        threadA.start();  

        try { Thread.sleep(200); }   
        catch ( InterruptedException x ) { }  

        Runnable runB = new Runnable() {  
            public void run() {  
                obj2.checkOther(obj1);  
            }  
        };  

        Thread threadB = new Thread(runB, "threadB");  
        threadB.start();  

        try { Thread.sleep(5000); }   
        catch ( InterruptedException x ) { }  

        threadPrint("finished sleeping");  

        threadPrint("about to interrupt() threadA"); 

        threadA.interrupt();  

        try { Thread.sleep(1000); }   
        catch ( InterruptedException x ) { }  

        threadPrint("about to interrupt() threadB");  
        threadB.interrupt();  

        try { Thread.sleep(1000); }   
        catch ( InterruptedException x ) { }  

        threadPrint("did that break the deadlock?");  
    }
}

運行結(jié)果:

threadA: objID=obj1 - entering checkOther()
threadB: objID=obj2 - entering checkOther()
threadA: objID=obj1 - in checkOther() - about to invoke 'other.action()'
threadB: objID=obj2 - in checkOther() - about to invoke 'other.action()'
main: finished sleeping
main: about to interrupt() threadA
main: about to interrupt() threadB
main: did that break the deadlock?

從結(jié)果中可以看出苇经,在執(zhí)行到other.action()時赘理,由于兩個線程都在試圖獲取對方的鎖,但對方都沒有釋放自己的鎖扇单,因而便產(chǎn)生了死鎖商模,在主線程中試圖中斷兩個線程,但都無果蜘澜。

大部分代碼并不容易產(chǎn)生死鎖施流,死鎖可能在代碼中隱藏相當(dāng)長的時間,等待不常見的條件地發(fā)生鄙信,但即使是很小的概率瞪醋,一旦發(fā)生,便可能造成毀滅性的破壞装诡。避免死鎖是一件困難的事银受,遵循以下原則有助于規(guī)避死鎖:

  1. 只在必要的最短時間內(nèi)持有鎖,考慮使用同步語句塊代替整個同步方法鸦采;
  2. 盡量編寫不在同一時刻需要持有多個鎖的代碼宾巍,如果不可避免,則確保線程持有第二個鎖的時間盡量短暫渔伯;
  3. 創(chuàng)建和使用一個大鎖來代替若干小鎖顶霞,并把這個鎖用于互斥,而不是用作單個對象的對象級別鎖锣吼;

可重入內(nèi)置鎖

每個Java對象都可以用做一個實現(xiàn)同步的鎖确丢,這些鎖被稱為內(nèi)置鎖或監(jiān)視器鎖。線程在進入同步代碼塊之前會自動獲取鎖吐限,并且在退出同步代碼塊時會自動釋放鎖鲜侥。獲得內(nèi)置鎖的唯一途徑就是進入由這個鎖保護的同步代碼塊或方法。

當(dāng)某個線程請求一個由其他線程持有的鎖時诸典,發(fā)出請求的線程就會阻塞描函。然而,由于內(nèi)置鎖是可重入的狐粱,因此如果摸個線程試圖獲得一個已經(jīng)由它自己持有的鎖舀寓,那么這個請求就會成功〖◎撸“重入”意味著獲取鎖的操作的粒度是“線程”互墓,而不是調(diào)用。重入的一種實現(xiàn)方法是蒋搜,為每個鎖關(guān)聯(lián)一個獲取計數(shù)值和一個所有者線程篡撵。當(dāng)計數(shù)值為0時判莉,這個鎖就被認(rèn)為是沒有被任何線程所持有,當(dāng)線程請求一個未被持有的鎖時育谬,JVM將記下鎖的持有者券盅,并且將獲取計數(shù)值置為1,如果同一個線程再次獲取這個鎖膛檀,計數(shù)值將遞增锰镀,而當(dāng)線程退出同步代碼塊時,計數(shù)器會相應(yīng)地遞減咖刃。當(dāng)計數(shù)值為0時泳炉,這個鎖將被釋放。

重入進一步提升了加鎖行為的封裝性嚎杨,因此簡化了面向?qū)ο蟛l(fā)代碼的開發(fā)花鹅。分析如下程序:

public class Father  
{  
    public synchronized void doSomething(){  
        ......  
    }  
}  

public class Child extends Father  
{  
    public synchronized void doSomething(){  
        ......  
        super.doSomething();  
    }  
}  

子類覆寫了父類的同步方法,然后調(diào)用父類中的方法磕潮,此時如果沒有可重入的鎖翠胰,那么這段代碼件產(chǎn)生死鎖容贝。

由于Fither和Child中的doSomething方法都是synchronized方法自脯,因此每個doSomething方法在執(zhí)行前都會獲取Child對象實例上的鎖。如果內(nèi)置鎖不是可重入的斤富,那么在調(diào)用super.doSomething時將無法獲得該Child對象上的互斥鎖膏潮,因為這個鎖已經(jīng)被持有,從而線程會永遠阻塞下去满力,一直在等待一個永遠也無法獲取的鎖焕参。重入則避免了這種死鎖情況的發(fā)生。

同一個線程在調(diào)用本類中其他synchronized方法/塊或父類中的synchronized方法/塊時油额,都不會阻礙該線程地執(zhí)行叠纷,因為互斥鎖時可重入的。

使用wait/notify/notifyAll實現(xiàn)線程間通信

在Java中潦嘶,可以通過配合調(diào)用Object對象的wait()方法和notify()方法或notifyAll()方法來實現(xiàn)線程間的通信涩嚣。在線程中調(diào)用wait()方法,將阻塞等待其他線程的通知(其他線程調(diào)用notify()方法或notifyAll()方法)掂僵,在線程中調(diào)用notify()方法或notifyAll()方法航厚,將通知其他線程從wait()方法處返回。

Object是所有類的超類锰蓬,它有5個方法組成了等待/通知機制的核心:notify()幔睬、notifyAll()、wait()芹扭、wait(long)和wait(long麻顶,int)赦抖。在Java中,所有的類都從Object繼承而來澈蚌,因此摹芙,所有的類都擁有這些共有方法可供使用。而且宛瞄,由于他們都被聲明為final浮禾,因此在子類中不能覆寫任何一個方法。

這里詳細說明一下各個方法在使用中需要注意的幾點:

1份汗、wait()

public final void wait()  throws InterruptedException,IllegalMonitorStateException

該方法用來將當(dāng)前線程置入休眠狀態(tài)盈电,直到接到通知或被中斷為止。在調(diào)用wait()之前杯活,線程必須要獲得該對象的對象級別鎖匆帚,即只能在同步方法或同步塊中調(diào)用wait()方法。進入wait()方法后旁钧,當(dāng)前線程釋放鎖吸重。在從wait()返回前,線程與其他線程競爭重新獲得鎖歪今。如果調(diào)用wait()時嚎幸,沒有持有適當(dāng)?shù)逆i,則拋出IllegalMonitorStateException寄猩,它是RuntimeException的一個子類嫉晶,因此,不需要try-catch結(jié)構(gòu)田篇。

2替废、notify()

public final native void notify() throws IllegalMonitorStateException

該方法也要在同步方法或同步塊中調(diào)用,即在調(diào)用前泊柬,線程也必須要獲得該對象的對象級別鎖椎镣,的如果調(diào)用notify()時沒有持有適當(dāng)?shù)逆i,也會拋出IllegalMonitorStateException兽赁。

該方法用來通知那些可能等待該對象的對象鎖的其他線程状答。如果有多個線程等待,則線程規(guī)劃器任意挑選出其中一個wait()狀態(tài)的線程來發(fā)出通知闸氮,并使它等待獲取該對象的對象鎖(notify后剪况,當(dāng)前線程不會馬上釋放該對象鎖,wait所在的線程并不能馬上獲取該對象鎖蒲跨,要等到程序退出synchronized代碼塊后译断,當(dāng)前線程才會釋放鎖,wait所在的線程也才可以獲取該對象鎖)或悲,但不驚動其他同樣在等待被該對象notify的線程們孙咪。當(dāng)?shù)谝粋€獲得了該對象鎖的wait線程運行完畢以后堪唐,它會釋放掉該對象鎖,此時如果該對象沒有再次使用notify語句翎蹈,則即便該對象已經(jīng)空閑淮菠,其他wait狀態(tài)等待的線程由于沒有得到該對象的通知,會繼續(xù)阻塞在wait狀態(tài)荤堪,直到這個對象發(fā)出一個notify或notifyAll合陵。這里需要注意:它們等待的是被notify或notifyAll,而不是鎖澄阳。這與下面的notifyAll()方法執(zhí)行后的情況不同拥知。

3、notifyAll()

public final native void notifyAll() throws IllegalMonitorStateException

該方法與notify()方法的工作方式相同碎赢,重要的一點差異是:

notifyAll使所有原來在該對象上wait的線程統(tǒng)統(tǒng)退出wait的狀態(tài)(即全部被喚醒低剔,不再等待notify或notifyAll,但由于此時還沒有獲取到該對象鎖肮塞,因此還不能繼續(xù)往下執(zhí)行)襟齿,變成等待獲取該對象上的鎖,一旦該對象鎖被釋放(notifyAll線程退出調(diào)用了notifyAll的synchronized代碼塊的時候)枕赵,他們就會去競爭猜欺。如果其中一個線程獲得了該對象鎖,它就會繼續(xù)往下執(zhí)行烁设,在它退出synchronized代碼塊替梨,釋放鎖后钓试,其他的已經(jīng)被喚醒的線程將會繼續(xù)競爭獲取該鎖装黑,一直進行下去,直到所有被喚醒的線程都執(zhí)行完畢弓熏。

4恋谭、wait(long)和wait(long,int)

顯然,這兩個方法是設(shè)置等待超時時間的挽鞠,后者在超值時間上加上ns疚颊,精度也難以達到,因此信认,該方法很少使用材义。對于前者,如果在等待線程接到通知或被中斷之前嫁赏,已經(jīng)超過了指定的毫秒數(shù)其掂,則它通過競爭重新獲得鎖,并從wait(long)返回潦蝇。另外款熬,需要知道深寥,如果設(shè)置了超時時間蔚袍,當(dāng)wait()返回時舞箍,我們不能確定它是因為接到了通知還是因為超時而返回的,因為wait()方法不會返回任何相關(guān)的信息悔据。但一般可以通過設(shè)置標(biāo)志位來判斷殉簸,在notify之前改變標(biāo)志位的值闰集,在wait()方法后讀取該標(biāo)志位的值來判斷,當(dāng)然為了保證notify不被遺漏般卑,我們還需要另外一個標(biāo)志位來循環(huán)判斷是否調(diào)用wait()方法返十。

深入理解:

  • 如果線程調(diào)用了對象的wait()方法,那么線程便會處于該對象的等待池中椭微,等待池中的線程不會去競爭該對象的鎖洞坑。
  • 當(dāng)有線程調(diào)用了對象的notifyAll()方法(喚醒所有wait線程)或notify()方法(只隨機喚醒一個wait線程),被喚醒的的線程便會進入該對象的鎖池中蝇率,鎖池中的線程會去競爭該對象鎖迟杂。
  • 優(yōu)先級高的線程競爭到對象鎖的概率大,假若某線程沒有競爭到該對象鎖本慕,它還會留在鎖池中排拷,唯有線程再次調(diào)用wait()方法,它才會重新回到等待池中锅尘。而競爭到對象鎖的線程則繼續(xù)往下執(zhí)行监氢,直到執(zhí)行完了synchronized代碼塊,它會釋放掉該對象鎖藤违,這時鎖池中的線程會繼續(xù)競爭該對象鎖浪腐。

線程中斷

參考:

線程中斷

Error 和 Exception

Error與Exception的區(qū)別

Error是Throwable的子類,用于標(biāo)記嚴(yán)重錯誤顿乒。合理的應(yīng)用程序不應(yīng)該去try/catch這種錯誤议街。絕大多數(shù)的錯誤都是非正常的,就根本不該出現(xiàn)的璧榄。

Exception 是Throwable的一種形式的子類特漩,用于指示一種合理的程序想去catch的條件。即它僅僅是一種程序運行條件骨杂,而非嚴(yán)重錯誤涂身,并且鼓勵用戶程序去catch它。

checked exceptions: 通常是從一個可以恢復(fù)的程序中拋出來的搓蚪,并且最好能夠從這種異常中使用程序恢復(fù)蛤售。比如FileNotFoundException, ParseException等。

unchecked exceptions: 通常是如果一切正常的話本不該發(fā)生的異常,但是的確發(fā)生了悍抑。比如ArrayIndexOutOfBoundException, ClassCastException等鳄炉。從語言本身的角度講,程序不該去catch這類異常搜骡,雖然能夠從諸如RuntimeException這樣的異常中catch并恢復(fù)拂盯,但是并不鼓勵終端程序員這么做,因為完全沒要必要记靡。因為這類錯誤本身就是bug谈竿,應(yīng)該被修復(fù),出現(xiàn)此類錯誤時程序就應(yīng)該立即停止執(zhí)行摸吠。 因此空凸,面對Errors和unchecked exceptions應(yīng)該讓程序自動終止執(zhí)行,程序員不該做諸如try/catch這樣的事情寸痢,而是應(yīng)該查明原因呀洲,修改代碼邏輯。

Java中的異常處理機制的簡單原理和應(yīng)用啼止。

JAVA語言如何進行異常處理道逗,關(guān)鍵字:throws,throw,try,catch,finally分別代表什么意義?在try塊中可以拋出異常嗎献烦?

Java通過面向?qū)ο蟮姆椒ㄟM行異常處理滓窍,把各種不同的異常進行分類,并提供了良好的接口巩那。在Java中吏夯,每個異常都是一個對象,它是Throwable類或其它子類的實例即横。當(dāng)一個方法出現(xiàn)異常后便拋出一個異常對象噪生,該對象中包含有異常信息,調(diào)用這個對象的方法可以捕獲到這個異常并進行處理令境。Java的異常處理是通過5個關(guān)鍵詞來實現(xiàn)的:try杠园、catch顾瞪、throw舔庶、throws和finally。一般情況下是用try來執(zhí)行一段程序陈醒,如果出現(xiàn)異常惕橙,系統(tǒng)會拋出(throws)一個異常,這時候你可以通過它的類型來捕捉(catch)它钉跷,或最后(finally)由缺省處理器來處理弥鹦。用try來指定一塊預(yù)防所有“異常”的程序。緊跟在try程序后面彬坏,應(yīng)包含一個catch子句來指定你想要捕捉的“異畴伲”的類型。throw語句用來明確地拋出一個“異乘ㄊ迹”务冕。throws用來標(biāo)明一個成員函數(shù)可能拋出的各種“異常”幻赚。Finally為確保一段代碼不管發(fā)生什么“異迟饕洌”都被執(zhí)行一段代碼÷淠眨可以在一個成員函數(shù)調(diào)用的外面寫一個try語句箩退,在這個成員函數(shù)內(nèi)部寫另一個try語句保護其他代碼。每當(dāng)遇到一個try語句佳谦,“異炒骼裕”的框架就放到堆棧上面,直到所有的try語句都完成钻蔑。如果下一級的try語句沒有對某種“異澈袄ǎ”進行處理,堆棧就會展開矢棚,直到遇到有處理這種“異持J玻”的try語句。

try{ return} catch{} finally{}; return 還是 finally 先執(zhí)行蒲肋。

任何執(zhí)行try 或者catch中的return語句之前蘑拯,都會先執(zhí)行finally語句,如果finally存在的話兜粘。

如果finally中有return語句申窘,那么程序就return了,所以finally中的return是一定會被return的孔轴。

在try語句中剃法,在執(zhí)行return語句時,要返回的結(jié)果已經(jīng)準(zhǔn)備好了路鹰,就在此時贷洲,程序轉(zhuǎn)到finally執(zhí)行了。在轉(zhuǎn)去之前晋柱,try中先把要返回的結(jié)果存放到不同于x的局部變量中去优构,執(zhí)行完finally之后,在從中取出返回結(jié)果雁竞,因此钦椭,即使finally中對變量x進行了改變,但是不會影響返回結(jié)果。

序列化

對象Object讀寫的是哪兩個流

ObjectInputStream

ObjectOutputStream

什么是Java序列化彪腔,如何實現(xiàn)java序列化

序列化就是一種用來處理對象流的機制侥锦,所謂對象流也就是將對象的內(nèi)容進行流化〉抡酰可以對流化后的對象進行讀寫操作捎拯,也可將流化后的對象傳輸于網(wǎng)絡(luò)之間。序列化是為了解決在對對象流進行讀寫操作時所引發(fā)的問題盲厌。

序列化的實現(xiàn):將需要被序列化的類實現(xiàn)Serializable接口署照,該接口沒有需要實現(xiàn)的方法,implements Serializable只是為了標(biāo)注該對象是可被序列化的吗浩,然后使用一個輸出流(如:FileOutputStream)來構(gòu)造一個ObjectOutputStream(對象流)對象建芙,接著,使用ObjectOutputStream對象的writeObject(Object obj)方法就可以將參數(shù)為obj的對象寫出(即保存其狀態(tài))懂扼,要恢復(fù)的話則用輸入流禁荸。

Serializable和Parcelable

注解

注解原理

反射

反射原理

反射機制

java反射機制是在運行狀態(tài)中,對于任意一個類阀湿, 都能夠知道這個類的所有屬性和方法赶熟;對于任意一個對象, 都能夠調(diào)用它的任意一個方法和屬性陷嘴;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機制映砖。

主要作用有三:

  1. 運行時取得類的方法和字段的相關(guān)信息。
  2. 創(chuàng)建某個類的新實例(.newInstance())
  3. 取得字段引用直接獲取和設(shè)置對象字段灾挨,無論訪問修飾符是什么邑退。

用處如下:

  1. 觀察或操作應(yīng)用程序的運行時行為。
  2. 調(diào)試或測試程序劳澄,因為可以直接訪問方法地技、構(gòu)造函數(shù)和成員字段。
  3. 通過名字調(diào)用不知道的方法并使用該信息來創(chuàng)建對象和調(diào)用方法秒拔。

Java類加載機制

泛型

泛型的優(yōu)缺點

優(yōu)點:

使用泛型類型可以最大限度地重用代碼莫矗、保護類型的安全以及提高性能。泛型最常見的用途是創(chuàng)建集合類砂缩。

缺點:

在性能上不如數(shù)組快作谚。

泛型常用特點,List<String>能否轉(zhuǎn)為List<Object>

能梯轻,但是利用類都繼承自O(shè)bject食磕,所以使用是每次調(diào)用里面的函數(shù)都要通過強制轉(zhuǎn)換還原回原來的類,這樣既不安全喳挑,運行速度也慢。

網(wǎng)絡(luò)

TCP與UDP的區(qū)別

TCP UDP
TCP面向有鏈接的通信服務(wù) UDP面向無連接的通信服務(wù)
TCP提供可靠的通信傳輸 UDP不可靠,會丟包
TCP保證數(shù)據(jù)順序 UDP不保證
TCP數(shù)據(jù)無邊界 UDP有邊界
TCP速度慢 UDP速度快
TCP面向字節(jié)流 UDP面向報文
TCP一對一 UDP可以一對一伊诵,一對多
TCP報頭至少20字節(jié) UDP報頭8字節(jié)
TCP有流量控制单绑,擁塞控制 UDP沒有

http get 和 post 的區(qū)別

  • GET請求的數(shù)據(jù)會附在URL之后(就是把數(shù)據(jù)放置在HTTP協(xié)議頭中),以?分割URL和傳輸數(shù)據(jù)曹宴,參數(shù)之間以&相連搂橙,如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。如果數(shù)據(jù)是英文字母/數(shù)字笛坦,原樣發(fā)送区转,如果是空格,轉(zhuǎn)換為+版扩,如果是中文/其他字符废离,則直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD礁芦,其中%XX中的XX為該符號以16進制表示的ASCII蜻韭。

POST把提交的數(shù)據(jù)則放置在是HTTP包的包體中。

  • GET方式提交的數(shù)據(jù)最多只能是1024字節(jié)柿扣,理論上POST沒有限制肖方,可傳較大量的數(shù)據(jù)。

首先是"GET方式提交的數(shù)據(jù)最多只能是1024字節(jié)"未状,因為GET是通過URL提交數(shù)據(jù)俯画,那么GET可提交的數(shù)據(jù)量就跟URL的長度有直接關(guān)系了。而實際上司草,URL不存在參數(shù)上限的問題活翩,HTTP協(xié)議規(guī)范沒有對URL長度進行限制。這個限制是特定的瀏覽器及服務(wù)器對它的限制翻伺。IE對URL長度的限制是2083字節(jié)(2K+35)材泄。對于其他瀏覽器,如Netscape吨岭、FireFox等拉宗,理論上沒有長度限制,其限制取決于操作系統(tǒng)的支持辣辫。

注意這是限制是整個URL長度旦事,而不僅僅是你的參數(shù)值數(shù)據(jù)長度。

  • POST的安全性要比GET的安全性高急灭。注意:這里所說的安全性和上面GET提到的“安全”不是同個概念姐浮。上面“安全”的含義僅僅是不作數(shù)據(jù)修改,而這里安全的含義是真正的Security的含義葬馋,比如:通過GET提交數(shù)據(jù)卖鲤,用戶名和密碼將明文出現(xiàn)在URL上肾扰,因為(1)登錄頁面有可能被瀏覽器緩存,(2)其他人查看瀏覽器的歷史紀(jì)錄蛋逾,那么別人就可以拿到你的賬號和密碼了集晚。

GET - 從指定的服務(wù)器中獲取數(shù)據(jù)
POST - 提交數(shù)據(jù)給指定的服務(wù)器處理

GET方法:
使用GET方法時,查詢字符串(鍵值對)被附加在URL地址后面一起發(fā)送到服務(wù)器:
/test/demo_form.jsp?name1=value1&name2=value2
特點:

GET請求能夠被緩存
GET請求會保存在瀏覽器的瀏覽記錄中
以GET請求的URL能夠保存為瀏覽器書簽
GET請求有長度限制
GET請求主要用以獲取數(shù)據(jù)

POST方法:
使用POST方法時区匣,查詢字符串在POST信息中單獨存在偷拔,和HTTP請求一起發(fā)送到服務(wù)器:
POST /test/demo_form.jsp HTTP/1.1
Host: w3schools.com
name1=value1&name2=value2
特點:

POST請求不能被緩存下來
POST請求不會保存在瀏覽器瀏覽記錄中
以POST請求的URL無法保存為瀏覽器書簽
POST請求沒有長度限制
Post一般用于更新或者添加資源信息 Get一般用于查詢操作,而且應(yīng)該是安全和冪等的
Post更加安全 Get會把請求的信息放到URL的后面
Post傳輸量一般無大小限制 Get不能大于2KB
Post執(zhí)行效率低 Get執(zhí)行效率略高

https的那個s是什么意思

UDP 和 TCP 的區(qū)別

  1. 基于連接與無連接亏钩;
  2. 對系統(tǒng)資源的要求(TCP較多莲绰,UDP少);
  3. UDP程序結(jié)構(gòu)較簡單姑丑;
  4. 流模式與數(shù)據(jù)包模式 蛤签;
  5. TCP保證數(shù)據(jù)正確性,UDP可能丟包彻坛,TCP保證數(shù)據(jù)順序顷啼,UDP不保證。

TCP:面向連接昌屉、傳輸可靠(保證數(shù)據(jù)正確性,保證數(shù)據(jù)順序)钙蒙、用于傳輸大量數(shù)據(jù)(流模式)、速度慢间驮,建立連接需要開銷較多(時間躬厌,系統(tǒng)資源)。

UDP:面向非連接竞帽、傳輸不可靠扛施、用于傳輸少量數(shù)據(jù)(數(shù)據(jù)包模式)、速度快屹篓。


TCP是Tranfer Control Protocol的 簡稱疙渣,是一種面向連接的保證可靠傳輸?shù)膮f(xié)議。通過TCP協(xié)議傳輸堆巧,得到的是一個順序的無差錯的數(shù)據(jù)流妄荔。發(fā)送方和接收方的成對的兩個socket之間必須建 立連接,以便在TCP協(xié)議的基礎(chǔ)上進行通信谍肤,當(dāng)一個socket(通常都是server socket)等待建立連接時啦租,另一個socket可以要求進行連接,一旦這兩個socket連接起來荒揣,它們就可以進行雙向數(shù)據(jù)傳輸篷角,雙方都可以進行發(fā)送 或接收操作。

UDP是User Datagram Protocol的簡稱系任,是一種無連接的協(xié)議恳蹲,每個數(shù)據(jù)報都是一個獨立的信息虐块,包括完整的源地址或目的地址,它在網(wǎng)絡(luò)上以任何可能的路徑傳往目的地阱缓,因此能否到達目的地非凌,到達目的地的時間以及內(nèi)容的正確性都是不能被保證的举农。

比較:

UDP:

1荆针,每個數(shù)據(jù)報中都給出了完整的地址信息,因此無需要建立發(fā)送方和接收方的連接颁糟。

2航背,UDP傳輸數(shù)據(jù)時是有大小限制的,每個被傳輸?shù)臄?shù)據(jù)報必須限定在64KB之內(nèi)棱貌。

3玖媚,UDP是一個不可靠的協(xié)議,發(fā)送方所發(fā)送的數(shù)據(jù)報并不一定以相同的次序到達接收方

TCP:

1婚脱,面向連接的協(xié)議今魔,在socket之間進行數(shù)據(jù)傳輸之前必然要建立連接,所以在TCP中需要連接時間障贸。

2错森,TCP傳輸數(shù)據(jù)大小限制,一旦連接建立起來篮洁,雙方的socket就可以按統(tǒng)一的格式傳輸大的數(shù)據(jù)涩维。

3,TCP是一個可靠的協(xié)議袁波,它確保接收方完全正確地獲取發(fā)送方所發(fā)送的全部數(shù)據(jù)瓦阐。

應(yīng)用:

1,TCP在網(wǎng)絡(luò)通信上有極強的生命力篷牌,例如遠程連接(Telnet)和文件傳輸(FTP)都需要不定長度的數(shù)據(jù)被可靠地傳輸睡蟋。但是可靠的傳輸是要付出代價的,對數(shù)據(jù)內(nèi)容正確性的檢驗必然占用計算機的處理時間和網(wǎng)絡(luò)的帶寬枷颊,因此TCP傳輸?shù)男什蝗鏤DP高戳杀。

2,UDP操作簡單偷卧,而且僅需要較少的監(jiān)護豺瘤,因此通常用于局域網(wǎng)高可靠性的分散系統(tǒng)中client/server應(yīng)用程序。例如視頻會議系統(tǒng)听诸,并不要求音頻視頻數(shù)據(jù)絕對的正確坐求,只要保證連貫性就可以了,這種情況下顯然使用UDP會更合理一些晌梨。

TCP與UDP

面向報文的傳輸方式是應(yīng)用層交給UDP多長的報文桥嗤,UDP就照樣發(fā)送须妻,即一次發(fā)送一個報文。因此泛领,應(yīng)用程序必須選擇合適大小的報文荒吏。若報文太長,則IP層需要分片渊鞋,降低效率绰更。若太短,會是IP太小锡宋。UDP對應(yīng)用層交下來的報文儡湾,既不合并,也不拆分执俩,而是保留這些報文的邊界徐钠。這也就是說,應(yīng)用層交給UDP多長的報文役首,UDP就照樣發(fā)送尝丐,即一次發(fā)送一個報文。面向字節(jié)流的話衡奥,雖然應(yīng)用程序和TCP的交互是一次一個數(shù)據(jù)塊(大小不等)爹袁,但TCP把應(yīng)用程序看成是一連串的無結(jié)構(gòu)的字節(jié)流。TCP有一個緩沖杰赛,當(dāng)應(yīng)用程序傳送的數(shù)據(jù)塊太長呢簸,TCP就可以把它劃分短一些再傳送。如果應(yīng)用程序一次只發(fā)送一個字節(jié)乏屯,TCP也可以等待積累有足夠多的字節(jié)后再構(gòu)成報文段發(fā)送出去根时。

TCP協(xié)議

  • Transmission Control Protocol,傳輸控制協(xié)議
  • 面向連接的協(xié)議
  • 需要三次握手建立連接
  • 需要四次揮手?jǐn)嚅_連接
  • TCP報頭最小長度:20字節(jié)

三次握手的過程:

  1. 客戶端發(fā)送:SYN = 1, SEQ = X, 端口號
  2. 服務(wù)器回復(fù):SYN = 1, ACK = X + 1, SEQ = Y
  3. 客戶端發(fā)送:ACK = Y + 1, SEQ = X + 1

確認(rèn)應(yīng)答信號ACK = 收到的SEQ + 1辰晕。連接建立中蛤迎,同步信號SYN始終為1。連接建立后含友,同步信號SYN=0替裆。

四次揮手過程

  1. A向B提出停止連接請求,F(xiàn)IN = 1
  2. B收到窘问,ACK = 1
  3. B向A提出停止連接請求辆童,F(xiàn)IN = 1
  4. A收到,ACK = 1

優(yōu)點:

  • 可靠惠赫,穩(wěn)定 1把鉴、傳遞數(shù)據(jù)前恍箭,會有三次握手建立連接 2挪钓、傳遞數(shù)據(jù)時,有確認(rèn)捻浦、窗口咆爽、重傳霉翔、擁塞控制 3樟蠕、傳遞數(shù)據(jù)后嗅义,會斷開連接節(jié)省系統(tǒng)資源

缺點:

  • 傳輸慢,效率低揭北,占用系統(tǒng)資源高1扳炬、傳遞數(shù)據(jù)前,建立連接需要耗時2罐呼、傳遞數(shù)據(jù)時鞠柄,確認(rèn)侦高、重傳嫉柴、擁塞等會消耗大量時間以及CPU和內(nèi)存等硬件資源
  • 易被攻擊1、因為有確認(rèn)機制奉呛,三次握手等機制计螺,容易被人利用,實現(xiàn)DOS 瞧壮、DDOS攻擊

如何保證接收的順序性:
TCP協(xié)議使用SEQ和ACK機制保證了順序性TCP的每個報文都是有序號的登馒。確認(rèn)應(yīng)答信號ACK=收到的SEQ+1

TCP的三次握手,和四次揮手咆槽,為什么需要三次握手陈轿,為什么要四次揮手

UDP協(xié)議

  • User Data Protocol,用戶數(shù)據(jù)包協(xié)議
  • 面向無連接的協(xié)議
  • UDP報頭只有8字節(jié)

簡介:

  • 傳輸數(shù)據(jù)之前源端和終端不建立連接秦忿,當(dāng)它想傳送時就簡單地去抓取來自應(yīng)用程序的數(shù)據(jù)麦射,并盡可能快的把它扔到網(wǎng)絡(luò)上
  • 在發(fā)送端,UDP傳送數(shù)據(jù)的速度僅僅是受應(yīng)用程序生成數(shù)據(jù)的速度灯谣、計算機的能力和傳輸帶寬的限制
  • 在接收端潜秋,UDP把每個消息段放在隊列中,應(yīng)用程序每次從隊列中讀一個消息段
  • 由于傳輸數(shù)據(jù)不建立連接胎许,因此也就不需要維護連接狀態(tài)峻呛,包括收發(fā)狀態(tài)等,因此一臺服務(wù)機可同時向多個客戶機傳輸相同的消息
  • UDP信息包的標(biāo)題很短辜窑,只有8個字節(jié)钩述,相對于TCP的20個字節(jié)信息包的額外開銷很小
  • 吞吐量不受擁擠控制算法的調(diào)節(jié),只受應(yīng)用軟件生成數(shù)據(jù)的速率穆碎、傳輸帶寬牙勘、源端和終端主機性能的限制
  • UDP使用盡最大努力交付,即不保證可靠交付惨远,因此主機不需要維持復(fù)雜的鏈接狀態(tài)表谜悟。
  • UDP是面向報文的话肖。發(fā)送方的UDP對應(yīng)用程序交下來的報文,在添加首部后就向下交付給IP層葡幸。既不拆分最筒,也不合并,而是保留這些報文的邊界蔚叨,因此床蜘,應(yīng)用程序需要選擇合適的報文大小。

使用“ping”命令來測試兩臺主機之間TCP/IP通信是否正常蔑水,其實“ping”命令的原理就是向?qū)Ψ街鳈C發(fā)送UDP數(shù)據(jù)包邢锯,然后對方主機確認(rèn)收到數(shù)據(jù)包,如果數(shù)據(jù)包是否到達的消息及時反饋回來搀别,那么網(wǎng)絡(luò)就是通的丹擎。

優(yōu)點:

  • 傳輸速率快1、傳輸數(shù)據(jù)前歇父,不需要像TCP一樣建立連接2蒂培、傳輸數(shù)據(jù)時,沒有確認(rèn)榜苫、窗口护戳、重傳、擁塞控制等機制
  • 較安全1垂睬、由于沒有了TCP的一些機制媳荒,被攻擊者利用的漏洞就少了

缺點:

  • 不可靠,不穩(wěn)定1驹饺、由于沒有了TCP的機制钳枕,在數(shù)據(jù)傳輸時如果網(wǎng)絡(luò)不好,很可能丟包

用UDP協(xié)議通訊時怎樣得知目標(biāo)機是否獲得了數(shù)據(jù)包

仿造TCP的做法逻淌,每發(fā)一個UDP包么伯,都在里面加一個SEQ序號,接收方收到包后卡儒,將SEQ序號回復(fù)給發(fā)送方田柔。如果發(fā)送方在指定時間以內(nèi)沒有收到回應(yīng),說明丟包了骨望。

為什么UDP比TCP快

  1. TCP需要三次握手
  2. TCP有擁塞控制硬爆,控制流量等機制

為什么TCP比UDP可靠

  1. TCP是面向有連接的,建立連接之后才發(fā)送數(shù)據(jù)擎鸠;而UDP則不管對方存不存在都會發(fā)送數(shù)據(jù)缀磕。
  2. TCP有確認(rèn)機制,接收端每收到一個正確包都會回應(yīng)給發(fā)送端。超時或者數(shù)據(jù)包不完整的話發(fā)送端會重傳袜蚕。UDP沒有糟把,因此可能丟包。

什么時候使用TCP

當(dāng)對網(wǎng)絡(luò)通訊質(zhì)量有要求的時候牲剃,比如:整個數(shù)據(jù)要準(zhǔn)確無誤的傳遞給對方遣疯,這往往用于一些要求可靠的應(yīng)用,比如HTTP凿傅、HTTPS缠犀、FTP等傳輸文件的協(xié)議,POP聪舒、SMTP等郵件傳輸?shù)膮f(xié)議辨液。在日常生活中,常見使用TCP協(xié)議的應(yīng)用如下:瀏覽器箱残,用的HTTPFlashFXP滔迈,用的FTPOutlook,用的POP疚宇、SMTPPutty亡鼠,用的Telnet、SSHQQ文件傳輸

什么時候應(yīng)該使用UDP

當(dāng)對網(wǎng)絡(luò)通訊質(zhì)量要求不高的時候敷待,要求網(wǎng)絡(luò)通訊速度能盡量的快,這時就可以使用UDP仁热。比如榜揖,日常生活中,常見使用UDP協(xié)議的應(yīng)用如下:QQ語音QQ視頻TFTP

TCP無邊界抗蠢,UDP有邊界

TCP無邊界

客戶端分多次發(fā)送數(shù)據(jù)給服務(wù)器举哟,若服務(wù)器的緩沖區(qū)夠大,那么服務(wù)器端會在客戶端發(fā)送完之后一次性接收過來迅矛,所以是無邊界的妨猩;

UDP有邊界

客戶端每發(fā)送一次,服務(wù)器端就會接收一次秽褒,也就是說發(fā)送多少次就會接收多少次壶硅,因此是有邊界的。

Socket編程的步驟

Server端Listen(監(jiān)聽)某個端口是否有連接請求销斟,Client端向Server 端發(fā)出Connect(連接)請求庐椒,Server端向Client端發(fā)回Accept(接受)消息。一個連接就建立起來了蚂踊。Server端和Client 端都可以通過Send约谈,Write等方法與對方通信。

對于一個功能齊全的Socket,都要包含以下基本結(jié)構(gòu)棱诱,其工作過程包含以下四個基本的步驟:

(1) 創(chuàng)建Socket泼橘;

(2) 打開連接到Socket的輸入/出流;

(3) 按照一定的協(xié)議對Socket進行讀/寫操作迈勋;

(4) 關(guān)閉Socket.(在實際應(yīng)用中侥加,并未使用到顯示的close,雖然很多文章都推薦如此粪躬,不過在我的程序中担败,可能因為程序本身比較簡單,要求不高镰官,所以并未造成什么影響提前。)

IO

IO框架主要用到什么設(shè)計模式

JDK的I/O包中就主要使用到了兩種設(shè)計模式:Adatper模式和Decorator模式。

NIO包有哪些結(jié)構(gòu)泳唠?分別起到的作用狈网?

NIO

NIO針對什么情景會比IO有更好的優(yōu)化?

OKIO底層實現(xiàn)

json

JSON,fastjson 和 GSON的區(qū)別

1.json-lib

json-lib最開始的也是應(yīng)用最廣泛的json解析工具,json-lib 不好的地方確實是依賴于很多第三方包谆级,包括commons-beanutils.jar脚仔,commons-collections-3.2.jar,commons-lang-2.6.jar,commons-logging-1.1.1.jar,ezmorph-1.0.6.jar音半,
對于復(fù)雜類型的轉(zhuǎn)換,json-lib對于json轉(zhuǎn)換成bean還有缺陷,比如一個類里面會出現(xiàn)另一個類的list或者map集合,json-lib從json到bean的轉(zhuǎn)換就會出現(xiàn)問題。

json-lib在功能和性能上面都不能滿足現(xiàn)在互聯(lián)網(wǎng)化的需求葫督。

2.開源的Jackson

相比json-lib框架洽胶,Jackson所依賴的jar包較少领追,簡單易用并且性能也要相對高些些膨。而且Jackson社區(qū)相對比較活躍洼哎,更新速度也比較快。

Jackson對于復(fù)雜類型的json轉(zhuǎn)換bean會出現(xiàn)問題凭涂,一些集合Map白翻,List的轉(zhuǎn)換出現(xiàn)問題槐瑞。Jackson對于復(fù)雜類型的bean轉(zhuǎn)換Json,轉(zhuǎn)換的json格式不是標(biāo)準(zhǔn)的Json格式

3.Google的Gson

Gson是目前功能最全的Json解析神器那槽,Gson當(dāng)初是為因應(yīng)Google公司內(nèi)部需求而由Google自行研發(fā)而來骚灸,但自從在2008年五月公開發(fā)布第一版后已被許多公司或用戶應(yīng)用丈钙。

Gson的應(yīng)用主要為toJson與fromJson兩個轉(zhuǎn)換函數(shù),無依賴施逾,不需要例外額外的jar,能夠直接跑在JDK上榨汤。

而在使用這種對象轉(zhuǎn)換之前需先創(chuàng)建好對象的類型以及其成員才能成功的將JSON字符串成功轉(zhuǎn)換成相對應(yīng)的對象蠕搜。類里面只要有g(shù)et和set方法,Gson完全可以將復(fù)雜類型的json到bean或bean到j(luò)son的轉(zhuǎn)換收壕,是JSON解析的神器妓灌。

Gson在功能上面無可挑剔,但是性能上面比FastJson有所差距蜜宪。

4.阿里巴巴的FastJson

Fastjson是一個Java語言編寫的高性能的JSON處理器,由阿里巴巴公司開發(fā)虫埂。無依賴,不需要例外額外的jar圃验,能夠直接跑在JDK上掉伏。

FastJson在復(fù)雜類型的Bean轉(zhuǎn)換Json上會出現(xiàn)一些問題,可能會出現(xiàn)引用的類型澳窑,導(dǎo)致Json轉(zhuǎn)換出錯斧散,需要制定引用。

FastJson采用獨創(chuàng)的算法摊聋,將parse的速度提升到極致鸡捐,超過所有json庫。

xml

XML麻裁,解析XML的幾種方式的原理與特點:DOM闯参、SAX、PULL

參考:http://www.cnblogs.com/HaroldTihan/p/4316397.html

JNI

參考:http://landerlyoung.github.io/blog/2014/10/16/java-zhong-jnide-shi-yong/

MD5加密原理悲立,可否解密。

排序算法

常見排序算法的時間復(fù)雜度

Java 排序算法

參考:http://blog.csdn.net/qy1387/article/details/7752973

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末新博,一起剝皮案震驚了整個濱河市薪夕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赫悄,老刑警劉巖原献,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件馏慨,死亡現(xiàn)場離奇詭異,居然都是意外死亡姑隅,警方通過查閱死者的電腦和手機写隶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讲仰,“玉大人慕趴,你說我怎么就攤上這事”啥福” “怎么了冕房?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長趁矾。 經(jīng)常有香客問我耙册,道長,這世上最難降的妖魔是什么毫捣? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任详拙,我火速辦了婚禮,結(jié)果婚禮上蔓同,老公的妹妹穿的比我還像新娘饶辙。我一直安慰自己,他們只是感情好牌柄,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布畸悬。 她就那樣靜靜地躺著,像睡著了一般珊佣。 火紅的嫁衣襯著肌膚如雪蹋宦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天咒锻,我揣著相機與錄音冷冗,去河邊找鬼。 笑死惑艇,一個胖子當(dāng)著我的面吹牛蒿辙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播滨巴,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼思灌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了恭取?” 一聲冷哼從身側(cè)響起泰偿,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蜈垮,沒想到半個月后耗跛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體裕照,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年调塌,在試婚紗的時候發(fā)現(xiàn)自己被綠了晋南。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡羔砾,死狀恐怖负间,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蜒茄,我是刑警寧澤唉擂,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站檀葛,受9級特大地震影響玩祟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜屿聋,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一空扎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧润讥,春花似錦转锈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至脆粥,卻和暖如春砌溺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背变隔。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工规伐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人匣缘。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓猖闪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親肌厨。 傳聞我的和親對象是個殘疾皇子培慌,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 從三月份找實習(xí)到現(xiàn)在,面了一些公司柑爸,掛了不少检柬,但最終還是拿到小米、百度、阿里何址、京東、新浪进胯、CVTE用爪、樂視家的研發(fā)崗...
    時芥藍閱讀 42,240評論 11 349
  • (一)Java部分 1、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨云閱讀 7,101評論 0 62
  • 一胁镐、多線程 說明下線程的狀態(tài) java中的線程一共有 5 種狀態(tài)偎血。 NEW:這種情況指的是,通過 New 關(guān)鍵字創(chuàng)...
    Java旅行者閱讀 4,676評論 0 44
  • 夜已深盯漂,人未眠颇玷!淅瀝瀝的雨著實讓人心煩意亂, 雨將停就缆,心卻亂帖渠! 并不寂寞,因為有寂寞陪伴著我竭宰! ...
    余越閱讀 405評論 0 1
  • 問:如何培養(yǎng)批判性思維空郊? 答:1.多問How 2.多問why 3.多問why not 4.多與別...
    蘇不慢閱讀 3,169評論 4 51