java知識(shí)擴(kuò)展

jvm進(jìn)程

JVM進(jìn)程可以由bin\jps查看。在命令行下輸入jps

  1. 由一個(gè)jdk文件系統(tǒng),可以產(chǎn)生很多jvm進(jìn)程(沒bin\java.exe執(zhí)行后產(chǎn)生一個(gè))
  2. JVM進(jìn)程有個(gè)pid,默認(rèn)情況下河他執(zhí)行的main所在的類相同
  3. bin\jconsole 可以監(jiān)視和管理java程序
  4. jvm的三大財(cái)產(chǎn)
  • 內(nèi)存
    內(nèi)存是JVM擁有的主要財(cái)產(chǎn)之一,內(nèi)存你看到了分堆和非堆,這兩個(gè)值是 在執(zhí)行命令java.exe是可以修改的,如
    java.exe 類名 -Xmx3550m -Xms3550m -XX:MaxPermSize=16m
    -Xmx堆內(nèi)存最大
    -Xms堆內(nèi)存最小
    -XX:MaxPermSize 非堆 (放class,static var)

一般在實(shí)際的過程中將Xms與 Xmx設(shè)置為一樣。應(yīng)為避免程序執(zhí)行后期內(nèi)存不夠或分配不及時(shí)。這兩個(gè)值的大小將直接影響程序的性能<br />

在eclipse中,可以在點(diǎn)Run configurations...后界面設(shè)置.

  • 線程
    程啟動(dòng)運(yùn)行時(shí)會(huì)有一個(gè)線程去啟動(dòng)main方法
    除了main線程,其它都是JVM內(nèi)置的,我們自己沒有開啟.在實(shí)際運(yùn)行中,這里的線程太多和太少都不行,要維持在一個(gè)合理的范圍,而且也要時(shí)刻關(guān)注他們的狀態(tài)。如果程序中一個(gè)線程都沒有,那么進(jìn)程也死了。


  • 其實(shí)就是程序,包括JRE中的類,使用的第三方的jar
    包和我們應(yīng)用中自己寫的程序,這些類加載進(jìn)入內(nèi)存,都放在非堆中。
    所以我們JVM進(jìn)程是一個(gè)有身份證(pid),有姓名(名稱),擁有內(nèi)存,程類(程序)的一個(gè)靜態(tài)實(shí)體(CPU無法調(diào)度執(zhí)行)。

java類加載器基本知識(shí)

java web server 基本實(shí)現(xiàn)原理

  1. 遠(yuǎn)端服務(wù)器使用ServerSocket技術(shù)打開一個(gè)端口,等待請(qǐng)求的到來。
  2. 瀏覽器得到用戶輸入的地址(url)或者得到點(diǎn)擊聯(lián)接地址(url)。
  3. 瀏覽器看輸入的是IP還是域名,如果是域名,通過查找DNS服務(wù)找到此域名IP,并緩存到瀏覽器中,以加快下次查找速度。
  4. 瀏覽器組裝滿足HTTP協(xié)議的數(shù)據(jù)包(請(qǐng)求報(bào)文)。
  5. 瀏覽器請(qǐng)求在本機(jī)隨機(jī)開啟一個(gè)端口與服務(wù)端IP和服務(wù)端端口建立聯(lián)接 (TCP)。(本機(jī)IP + 本機(jī)端口 + 服務(wù)端IP + 服務(wù)端端口,用來唯一標(biāo)示一條TCP 聯(lián)接)
  6. 通過此聯(lián)接發(fā)送HTTP數(shù)據(jù)包。
  7. 服務(wù)端通過端口接收到數(shù)據(jù)之后,解析HTTP數(shù)據(jù)包,組裝成良好的格式,并調(diào)用程序處理。
  8. 服務(wù)程序處理完成之后,服務(wù)端組裝滿足HTTP協(xié)議的數(shù)據(jù)包(響應(yīng)報(bào)文)通過TCP聯(lián)接返回到請(qǐng)求端口上。
  9. 瀏覽器從請(qǐng)求端口得到數(shù)據(jù)解析響應(yīng)報(bào)文得到相應(yīng)數(shù)據(jù)后給瀏覽器軟件進(jìn)行解析渲染。
  10. 請(qǐng)求關(guān)閉聯(lián)接

先用socket技術(shù)實(shí)現(xiàn)一個(gè)main方法

public class WebServer {

    //服務(wù)端Socket只要一個(gè),所以定義成static, 同一時(shí)間只能一個(gè)線程訪問(主線程)
    private static ServerSocket ss;

    public static void main(String[] args) throws IOException {
        //綁定端口,只會(huì)執(zhí)行一次
        ss = new ServerSocket(8999);
        //主線程永遠(yuǎn)不死,所以用了個(gè)死循環(huán)
        while (true) {
            //這是一個(gè)IO阻塞式語句,也就是如果沒有請(qǐng)求(IO操作)進(jìn)來,當(dāng)前線程會(huì)在此等待,不再向下執(zhí)行
            Socket socket = ss.accept();


            //得到請(qǐng)求報(bào)文(內(nèi)容)
            StringBuffer sb = new StringBuffer();
            PrintWriter pw = null;
            try {
                InputStream socketIn = socket.getInputStream();
                BufferedReader br = new BufferedReader(new InputStreamReader(socketIn));
                while(true) {
                    String msg = br.readLine();
                    sb.append(msg);
                    System.out.println(msg);
                    if (msg == null || msg.trim().equals("")) {
                        break;
                    }
                }
                
                //輸入響應(yīng)報(bào)文
                pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));

                pw.println("HTTP/1.1 200 OK");
                pw.println("Content-Type: text/html;charset=UTF-8");
                pw.println();   //如果注釋掉這句,下面的html不會(huì)打印出來,未出頭部

                pw.write("html");
                pw.flush();

            } catch (IOException exception) {
                //TODO 處理異常
            } finally {
                socket.close();
                pw.close();
                //socket = null;
            }
        }
    }
}

啟動(dòng)程序后,在瀏覽器輸入http://127.0.0.1:8999/abc查看報(bào)文。

瀏覽器中的報(bào)文

但是上程序有一個(gè)問題,一個(gè)線程同一時(shí)間只能運(yùn)行一段代碼,在上面的例子中,邏輯處理是在主線程中運(yùn)行的(當(dāng)產(chǎn)生一個(gè)JVM進(jìn)程時(shí),同時(shí)會(huì)產(chǎn)生一個(gè)主線程,main方法中的代碼就是在主線程中執(zhí)行),當(dāng)一個(gè)請(qǐng)求還在處理邏輯和輸出時(shí),此時(shí)又來了一個(gè)請(qǐng)求,那么此請(qǐng)求將會(huì)被阻塞。所以我們可以把程序調(diào)整成如下樣子。

public class WebServer {

    //服務(wù)端Socket只要一個(gè),所以定義成static, 同一時(shí)間只能一個(gè)線程訪問
    private static ServerSocket ss;

    public static void main(String[] args) throws IOException {
        ss = new ServerSocket(8999);
        //有線程永遠(yuǎn)不死,所以用了個(gè)死循環(huán)
        while (true) {
            Socket socket = ss.accept();
            Thread thread = new Thread(new Handler(socket));
            thread.start();
        }
    }
}

public class Handler implements Runnable  {

    private Socket socket;
    public Handler(Socket socket){
        this.socket=socket;

    }
    @Override
    public void run() {
        StringBuffer sb = new StringBuffer();
        PrintWriter pw = null;
        try {
            InputStream socketIn = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(socketIn));
            while(true) {
                String msg = br.readLine();
                sb.append(msg);
                System.out.println(msg);
                if (msg == null || msg.trim().equals("")) {
                    break;
                }
            }
            pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));

            pw.println("HTTP/1.1 200 OK");
            pw.println("Content-Type: text/html;charset=UTF-8");
            pw.println();

            pw.write("html");
            pw.flush();

        } catch (IOException exception) {
            //TODO 處理異常
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            pw.close();
            //socket = null;
        }
    }
}

這中間的main方法相當(dāng)于一個(gè)公司的前臺(tái),將客戶(請(qǐng)求) 接入到公司,安排其他人來處理。
這樣每個(gè)請(qǐng)求一個(gè)線程,運(yùn)行完成后,線程就死了,這樣主線程負(fù)擔(dān)就輕了,不會(huì)發(fā)生阻塞了,但是新問題又來了,每個(gè)請(qǐng)求一個(gè)線程,那線程太多了,所以我們真正應(yīng)該使用線程池。

servlet注意點(diǎn)

  • servlet可以在web配置中設(shè)置容器一啟動(dòng)就被創(chuàng)建、初始化而不是第一個(gè)訪問后再被創(chuàng)建、初始化
    <load-on-startup>number(1or2or3)</load-on-startup>數(shù)字越小越早被創(chuàng)建、初始化

  • init(servletconfig) 可以從web.xml中獲取初始化數(shù)值。

  • servlet 中變量要定義在方法內(nèi),不允許放在servlet 下,防止線程串行,線程就不安全(如果這樣,會(huì)產(chǎn)生用戶a的線程進(jìn)行到一半,用戶b的線程進(jìn)來將用戶a的信息替換,用戶a有可能登陸到用戶b的賬號(hào))
    無狀態(tài)的對(duì)象(只有方法或變量為只讀)可以放在servlet第一層下。
    有狀態(tài)的對(duì)象(變量可以改變)注意線程安全問題。

線程注意點(diǎn)

  1. 線程、進(jìn)程、程序之間的關(guān)系
    CPU是所有進(jìn)程共同擁有的,所有進(jìn)程(包括所有JVM進(jìn)程和非JVM進(jìn)程)。大家都知道一個(gè)CPU在一個(gè)時(shí)間點(diǎn),只能運(yùn)行一行指令,也就是我們的程序,在Java中,所有程序都必須運(yùn)行在線程里,所以CPU是調(diào)度線程再運(yùn)行線程中的指令(程序),這些指令在運(yùn)行時(shí)會(huì)向它的進(jìn)程申請(qǐng)使用公共財(cái)產(chǎn)(堆內(nèi)存),同時(shí)線程也有自己的私有財(cái)產(chǎn)(棧內(nèi)存),這樣就構(gòu)成了”內(nèi)存(堆)”,”線程(棧內(nèi)存)”,”類(程序)”三者之間的關(guān)系,打個(gè)比方來說:
    一個(gè)家庭有夫妻兩個(gè),他們都有自己的小金庫(kù),同時(shí)也有家庭共同的財(cái)產(chǎn),丈夫在做一件事情時(shí),他要審請(qǐng)家庭財(cái)產(chǎn),同時(shí)要使用自己的小金庫(kù)才可以完成。那么在這個(gè)例子中,家庭就是一個(gè)進(jìn)程,夫妻是兩個(gè)線程,共同的財(cái)產(chǎn)是堆內(nèi)存,小金庫(kù)是棧內(nèi)存,事情就是類(程序)。夫妻在家庭這個(gè)空間中生存,如果夫妻兩人不幸都死了,那這個(gè)家庭就不存在了(相當(dāng)所有線程死了,進(jìn)程也就死了),但只要有一個(gè)還在,家庭就還在(進(jìn)程中只要有一個(gè)線程還存活,進(jìn)程就還存活)。
  2. 主線程的產(chǎn)生
    啟動(dòng)一個(gè)JVM進(jìn)程時(shí),JVM會(huì)自動(dòng)為我們創(chuàng)建一個(gè)線程,把它命名成”main”, 并把這個(gè)類中的main方法(程序)放到這個(gè)線程中的run方法中去執(zhí)行。
  3. java中產(chǎn)生線程的方式
    在java編程時(shí),除了main線程是由JVM為我們產(chǎn)生的以外,其它所有線程都由我們自己的程序生成。
    Java中定義線程的方式有兩種,繼承Thread和實(shí)現(xiàn)Runnable接口。我們來看如下程序:
package com.zhengmenbb.thread;
public class ChildThread implements Runnable {
   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
       for(long i = 0; i < Long.MAX_VALUE; i++) {
       }
   }
}

上面程序使用Runnable定義了一個(gè)線程類,在主程序(或者其它程序)中我們這樣調(diào)用:

package com.zhengmenbb.thread;
public class TestMain {

   public static void main(String[] args) {
       //System.out.println(Thread.currentThread().getName());
       Thread thread = new Thread(new ChildThread());
       thread.start();
   }
}

運(yùn)行main方法,你會(huì)看到生成的線程名字為:Thread-0, 當(dāng)然你可以通過thread這個(gè)線程對(duì)象引用來重設(shè)他的名字,優(yōu)先級(jí)等。使用jconsole我們打開這個(gè)進(jìn)程的線程tab頁:

Paste_Image.png

會(huì)發(fā)現(xiàn)main線程已死,但是Thread-0還活著,因?yàn)槲沂褂昧艘粋€(gè)時(shí)間很長(zhǎng)的循環(huán).這也證明了只要一個(gè)線程還活著,進(jìn)程是不會(huì)死的, 但如果你等把Thread-0中run方法執(zhí)行完成了,進(jìn)程就死了。記住,只要run方法中的代碼執(zhí)行完成了,線程就死了.


我們?cè)賮砜淳€程的另一種定義方法:繼承 Thread

package com.zhengmenbb.thread;
public class ChildThread1 extends Thread {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
        for(long i = 0; i < Long.MAX_VALUE; i++) {

        }
    }
}

在主程序(或者其它程序)中我們這樣調(diào)用:

package com.zhengmenbb.thread;
public class TestMain {

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        Thread thread = new ChildThread1();
        thread.start();
    }
}

兩種方式只是定義線程類方式不一樣,運(yùn)行時(shí)產(chǎn)生的線程是一樣的,強(qiáng)烈建議使用Runnable接口方式。

  1. ”用戶線程”和“守護(hù)線程”

請(qǐng)看如下代碼:

package com.zhengmenbb.thread;

public class TestMain {

    public static void main(String[] args) {

        Runtime.getRuntime().addShutdownHook(new Thread(){
            @Override
          public void run() {
          System.out.println("JVM 退出了");
          }
        });

        Thread thread = new Thread(new ChildThread());
        thread.setDaemon(true);
        thread.start();
    }
}  

在上面這段代碼中,我把線程的daemon(“守護(hù)”),設(shè)置了true, 你再運(yùn)行這段代碼,發(fā)現(xiàn)JVM進(jìn)程很快退出了。我們知道m(xù)ain線程run方法運(yùn)行很快,所以很快就死了,相當(dāng)妻子死了,Thread-0這個(gè)線程我們?cè)O(shè)置了daemon(“守護(hù)”),也就是說妻子死了,丈夫要守護(hù)她,也自殺隨她去了,這樣家庭(JVM)就死了。

那下面我們定義一個(gè)“用戶線程”和“守護(hù)線程”:

“用戶線程”: 只要有一個(gè)這樣的線程還活著,JVM就不會(huì)退出,這樣的線程我們定義為用戶線程. 其實(shí)是主線程和我們把daemon(“守護(hù)”),設(shè)置為false的線程。

“守護(hù)線程”:只要沒有用戶線程存活了,我就會(huì)自殺,這樣JVM主會(huì)退出。只要有用戶線程活著,我也活著。這一類線程我們稱為“守護(hù)線程”, 其實(shí)就是把daemon(“守護(hù)”),設(shè)置為true的線程。

值得一提的是,當(dāng)你在一個(gè)守護(hù)線程中產(chǎn)生了其他線程,那么這些新產(chǎn)生的線程不用設(shè)置Daemon屬性,都將是守護(hù)線程,用戶線程同樣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,610評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,668評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,004評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評(píng)論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,173評(píng)論 0 290
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,426評(píng)論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,656評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,833評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評(píng)論 1 295
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,371評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,621評(píng)論 2 380

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

  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,339評(píng)論 11 349
  • 一、認(rèn)識(shí)多任務(wù)、多進(jìn)程、單線程、多線程 要認(rèn)識(shí)多線程就要從操作系統(tǒng)的原理說起。 以前古老的DOS操作系統(tǒng)(V 6....
    GT921閱讀 1,024評(píng)論 0 3
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,829評(píng)論 18 139
  • 本文主要講了java中多線程的使用方法、線程同步、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法、概述等。 首先講...
    李欣陽閱讀 2,482評(píng)論 1 15
  • 為喪失提供的一個(gè)哀傷過程 --------心理咨詢手記 人的成長(zhǎng)過程中伴...
    恰如初閱讀 347評(píng)論 0 0