国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

深入淺出Java多線程

MarvinZhang / 2649人閱讀

摘要:當(dāng)狀態(tài)超時(shí)等待線程終止或者超時(shí)或者處理完畢時(shí),線程重新轉(zhuǎn)入就緒狀態(tài)。死亡狀態(tài)線程執(zhí)行完了或者因異常退出了方法,該線程結(jié)束生命周期。線程加入方法,等待其他線程終止。一系列線程以某種順序啟動(dòng)并不意味著將按該順序執(zhí)行。

初遇

Java給多線程編程提供了內(nèi)置的支持。一個(gè)多線程程序包含兩個(gè)或多個(gè)能并發(fā)運(yùn)行的部分。程序的每一部分都稱作一個(gè)線程,并且每個(gè)線程定義了一個(gè)獨(dú)立的執(zhí)行路徑。

多線程是多任務(wù)的一種特別的形式,但多線程使用了更小的資源開銷。

這里定義和線程相關(guān)的另一個(gè)術(shù)語 - 進(jìn)程:一個(gè)進(jìn)程包括由操作系統(tǒng)分配的內(nèi)存空間,包含一個(gè)或多個(gè)線程。一個(gè)線程不能獨(dú)立的存在,它必須是進(jìn)程的一部分。一個(gè)進(jìn)程一直運(yùn)行,直到所有的非守候線程都結(jié)束運(yùn)行后才能結(jié)束。

多線程能滿足程序員編寫高效率的程序來達(dá)到充分利用CPU的目的。

1. 多線程基礎(chǔ)概念介紹

進(jìn)程是程序(任務(wù))的執(zhí)行過程,它持有資源(共享內(nèi)存,共享文件)和線程

分析:

執(zhí)行過程 是動(dòng)態(tài)性的,你放在電腦磁盤上的某個(gè)eclipse或者QQ文件并不是我們的進(jìn)程,只有當(dāng)你雙擊運(yùn)行可執(zhí)行文件,使eclipse或者QQ運(yùn)行之后,這才稱為進(jìn)程。它是一個(gè)執(zhí)行過程,是一個(gè)動(dòng)態(tài)的概念。

它持有資源(共享內(nèi)存,共享文件)和線程:我們說進(jìn)程是資源的載體,也是線程的載體。這里的資源可以理解為內(nèi)存。我們知道程序是要從內(nèi)存中讀取數(shù)據(jù)進(jìn)行運(yùn)行的,所以每個(gè)進(jìn)程獲得執(zhí)行的時(shí)候會(huì)被分配一個(gè)內(nèi)存。

③ 線程是什么?

如果我們把進(jìn)程比作一個(gè)班級(jí),那么班級(jí)中的每個(gè)學(xué)生可以將它視作一個(gè)線程。學(xué)生是班級(jí)中的最小單元,構(gòu)成了班級(jí)中的最小單位。一個(gè)班級(jí)有可以多個(gè)學(xué)生,這些學(xué)生都使用共同的桌椅、書籍以及黑板等等進(jìn)行學(xué)習(xí)和生活。

在這個(gè)意義上我們說:

線程是系統(tǒng)中最小的執(zhí)行單元;同一進(jìn)程中可以有多個(gè)線程;線程共享進(jìn)程的資源。

④ 線程是如何交互?

就如同一個(gè)班級(jí)中的多個(gè)學(xué)生一樣,我們說多個(gè)線程需要通信才能正確的工作,這種通信,我們稱作線程的交互

交互的方式:互斥、同步

類比班級(jí),就是在同一班級(jí)之內(nèi),同學(xué)之間通過相互的協(xié)作才能完成某些任務(wù),有時(shí)這種協(xié)作是需要競(jìng)爭(zhēng)的,比如學(xué)習(xí),班級(jí)之內(nèi)公共的學(xué)習(xí)資料是有限的,愛學(xué)習(xí)的同學(xué)需要搶占它,需要競(jìng)爭(zhēng),當(dāng)一個(gè)同學(xué)使用完了之后另一個(gè)同學(xué)才可以使用;如果一個(gè)同學(xué)正在使用,那么其他新來的同學(xué)只能等待;另一方面需要同步協(xié)作,就好比班級(jí)六一需要排演節(jié)目,同學(xué)需要齊心協(xié)力相互配合才能將節(jié)目演好,這就是進(jìn)程交互。

一個(gè)線程的生命周期

線程經(jīng)過其生命周期的各個(gè)階段。下圖顯示了一個(gè)線程完整的生命周期。

新建狀態(tài):

使用 new 關(guān)鍵字和 Thread 類或其子類建立一個(gè)線程對(duì)象后,該線程對(duì)象就處于新建狀態(tài)。它保持這個(gè)狀態(tài)直到程序 start() 這個(gè)線程。

就緒狀態(tài):

當(dāng)線程對(duì)象調(diào)用了start()方法之后,該線程就進(jìn)入就緒狀態(tài)。就緒狀態(tài)的線程處于就緒隊(duì)列中,要等待JVM里線程調(diào)度器的調(diào)度。

運(yùn)行狀態(tài):

如果就緒狀態(tài)的線程獲取 CPU 資源,就可以執(zhí)行 run(),此時(shí)線程便處于運(yùn)行狀態(tài)。處于運(yùn)行狀態(tài)的線程最為復(fù)雜,它可以變?yōu)樽枞麪顟B(tài)、就緒狀態(tài)和死亡狀態(tài)。

阻塞狀態(tài):

如果一個(gè)線程執(zhí)行了sleep(睡眠)、suspend(掛起)等方法,失去所占用資源之后,該線程就從運(yùn)行狀態(tài)進(jìn)入阻塞狀態(tài)。在睡眠時(shí)間已到或獲得設(shè)備資源后可以重新進(jìn)入就緒狀態(tài)。

死亡狀態(tài):

一個(gè)運(yùn)行狀態(tài)的線程完成任務(wù)或者其他終止條件發(fā)生時(shí),該線程就切換到終止?fàn)顟B(tài)。

線程的狀態(tài)轉(zhuǎn)換圖

1、新建狀態(tài)(New):新創(chuàng)建了一個(gè)線程對(duì)象。

2、就緒狀態(tài)(Runnable):線程對(duì)象創(chuàng)建后,其他線程調(diào)用了該對(duì)象的start()方法。該狀態(tài)的線程位于可運(yùn)行線程池中,變得可運(yùn)行,等待獲取CPU的使用權(quán)。

3、運(yùn)行狀態(tài)(Running):就緒狀態(tài)的線程獲取了CPU,執(zhí)行程序代碼。

4、阻塞狀態(tài)(Blocked):阻塞狀態(tài)是線程因?yàn)槟撤N原因放棄CPU使用權(quán),暫時(shí)停止運(yùn)行。直到線程進(jìn)入就緒狀態(tài),才有機(jī)會(huì)轉(zhuǎn)到運(yùn)行狀態(tài)。阻塞的情況分三種:

(一)、等待阻塞:運(yùn)行的線程執(zhí)行wait()方法,JVM會(huì)把該線程放入等待池中。

(二)、同步阻塞:運(yùn)行的線程在獲取對(duì)象的同步鎖時(shí),若該同步鎖被別的線程占用,則JVM會(huì)把該線程放入鎖池中。

(三)、其他阻塞:運(yùn)行的線程執(zhí)行sleep()或join()方法,或者發(fā)出了I/O請(qǐng)求時(shí),JVM會(huì)把該線程置為阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時(shí)、join()等待線程終止或者超時(shí)、或者I/O處理完畢時(shí),線程重新轉(zhuǎn)入就緒狀態(tài)。

5、死亡狀態(tài)(Dead):線程執(zhí)行完了或者因異常退出了run()方法,該線程結(jié)束生命周期。

線程的調(diào)度

1、調(diào)整線程優(yōu)先級(jí):

每一個(gè)Java線程都有一個(gè)優(yōu)先級(jí),這樣有助于操作系統(tǒng)確定線程的調(diào)度順序。

Java線程的優(yōu)先級(jí)用整數(shù)表示,取值范圍是1~10,Thread類有以下三個(gè)靜態(tài)常量:
static int MAX_PRIORITY

      線程可以具有的最高優(yōu)先級(jí),取值為10。

static int MIN_PRIORITY

      線程可以具有的最低優(yōu)先級(jí),取值為1。

static int NORM_PRIORITY

      分配給線程的默認(rèn)優(yōu)先級(jí),取值為5。

Thread類的setPriority()和getPriority()方法分別用來設(shè)置和獲取線程的優(yōu)先級(jí)。
每個(gè)線程都有默認(rèn)的優(yōu)先級(jí)。主線程的默認(rèn)優(yōu)先級(jí)為Thread.NORM_PRIORITY。
線程的優(yōu)先級(jí)有繼承關(guān)系,比如A線程中創(chuàng)建了B線程,那么B將和A具有相同的優(yōu)先級(jí)。
JVM提供了10個(gè)線程優(yōu)先級(jí),但與常見的操作系統(tǒng)都不能很好的映射。如果希望程序能移植到各個(gè)操作系統(tǒng)中,應(yīng)該僅僅使用Thread類有以下三個(gè)靜態(tài)常量作為優(yōu)先級(jí),這樣能保證同樣的優(yōu)先級(jí)采用了同樣的調(diào)度方式。

具有較高優(yōu)先級(jí)的線程對(duì)程序更重要,并且應(yīng)該在低優(yōu)先級(jí)的線程之前分配處理器資源。但是,線程優(yōu)先級(jí)不能保證線程執(zhí)行的順序,而且非常依賴于平臺(tái)。

2、線程睡眠:Thread.sleep(long millis)方法,使線程轉(zhuǎn)到阻塞狀態(tài)。millis參數(shù)設(shè)定睡眠的時(shí)間,以毫秒為單位。當(dāng)睡眠結(jié)束后,就轉(zhuǎn)為就緒(Runnable)狀態(tài)。sleep()平臺(tái)移植性好。

3、線程等待:Object類中的wait()方法,導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 喚醒方法。這個(gè)兩個(gè)喚醒方法也是Object類中的方法,行為等價(jià)于調(diào)用 wait(0) 一樣。

4、線程讓步:Thread.yield() 方法,暫停當(dāng)前正在執(zhí)行的線程對(duì)象,把執(zhí)行機(jī)會(huì)讓給相同或者更高優(yōu)先級(jí)的線程。

5、線程加入:join()方法,等待其他線程終止。在當(dāng)前線程中調(diào)用另一個(gè)線程的join()方法,則當(dāng)前線程轉(zhuǎn)入阻塞狀態(tài),直到另一個(gè)進(jìn)程運(yùn)行結(jié)束,當(dāng)前線程再由阻塞轉(zhuǎn)為就緒狀態(tài)。

6、線程喚醒:Object類中的notify()方法,喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程。如果所有線程都在此對(duì)象上等待,則會(huì)選擇喚醒其中一個(gè)線程。選擇是任意性的,并在對(duì)實(shí)現(xiàn)做出決定時(shí)發(fā)生。線程通過調(diào)用其中一個(gè) wait 方法,在對(duì)象的監(jiān)視器上等待。 直到當(dāng)前的線程放棄此對(duì)象上的鎖定,才能繼續(xù)執(zhí)行被喚醒的線程。被喚醒的線程將以常規(guī)方式與在該對(duì)象上主動(dòng)同步的其他所有線程進(jìn)行競(jìng)爭(zhēng);例如,喚醒的線程在作為鎖定此對(duì)象的下一個(gè)線程方面沒有可靠的特權(quán)或劣勢(shì)。類似的方法還有一個(gè)notifyAll(),喚醒在此對(duì)象監(jiān)視器上等待的所有線程。

注意:Thread中suspend()和resume()兩個(gè)方法在JDK1.5中已經(jīng)廢除,不再介紹。因?yàn)橛兴梨i傾向。

7、常見線程名詞解釋
主線程:JVM調(diào)用程序main()所產(chǎn)生的線程。
當(dāng)前線程:這個(gè)是容易混淆的概念。一般指通過Thread.currentThread()來獲取的進(jìn)程。
后臺(tái)線程:指為其他線程提供服務(wù)的線程,也稱為守護(hù)線程。JVM的垃圾回收線程就是一個(gè)后臺(tái)線程。
前臺(tái)線程:是指接受后臺(tái)線程服務(wù)的線程,其實(shí)前臺(tái)后臺(tái)線程是聯(lián)系在一起,就像傀儡和幕后操縱者一樣的關(guān)系。傀儡是前臺(tái)線程、幕后操縱者是后臺(tái)線程。由前臺(tái)線程創(chuàng)建的線程默認(rèn)也是前臺(tái)線程。可以通過isDaemon()和setDaemon()方法來判斷和設(shè)置一個(gè)線程是否為后臺(tái)線程。

一些常見問題

1、線程的名字,一個(gè)運(yùn)行中的線程總是有名字的,名字有兩個(gè)來源,一個(gè)是虛擬機(jī)自己給的名字,一個(gè)是你自己的定的名字。在沒有指定線程名字的情況下,虛擬機(jī)總會(huì)為線程指定名字,并且主線程的名字總是main,非主線程的名字不確定。

2、線程都可以設(shè)置名字,也可以獲取線程的名字,連主線程也不例外。

3、獲取當(dāng)前線程的對(duì)象的方法是:Thread.currentThread();

4、每個(gè)線程都將啟動(dòng),每個(gè)線程都將運(yùn)行直到完成。一系列線程以某種順序啟動(dòng)并不意味著將按該順序執(zhí)行。對(duì)于任何一組啟動(dòng)的線程來說,調(diào)度程序不能保證其執(zhí)行次序,持續(xù)時(shí)間也無法保證。

5、當(dāng)線程目標(biāo)run()方法結(jié)束時(shí)該線程完成。

6、一旦線程啟動(dòng),它就永遠(yuǎn)不能再重新啟動(dòng)。只有一個(gè)新的線程可以被啟動(dòng),并且只能一次。一個(gè)可運(yùn)行的線程或死線程可以被重新啟動(dòng)。

7、線程的調(diào)度是JVM的一部分,在一個(gè)CPU的機(jī)器上上,實(shí)際上一次只能運(yùn)行一個(gè)線程。一次只有一個(gè)線程棧執(zhí)行。JVM線程調(diào)度程序決定實(shí)際運(yùn)行哪個(gè)處于可運(yùn)行狀態(tài)的線程。
眾多可運(yùn)行線程中的某一個(gè)會(huì)被選中做為當(dāng)前線程。可運(yùn)行線程被選擇運(yùn)行的順序是沒有保障的。

8、盡管通常采用隊(duì)列形式,但這是沒有保障的。隊(duì)列形式是指當(dāng)一個(gè)線程完成“一輪”時(shí),它移到可運(yùn)行隊(duì)列的尾部等待,直到它最終排隊(duì)到該隊(duì)列的前端為止,它才能被再次選中。事實(shí)上,我們把它稱為可運(yùn)行池而不是一個(gè)可運(yùn)行隊(duì)列,目的是幫助認(rèn)識(shí)線程并不都是以某種有保障的順序排列唱呢個(gè)一個(gè)隊(duì)列的事實(shí)。

9、盡管我們沒有無法控制線程調(diào)度程序,但可以通過別的方式來影響線程調(diào)度的方式。

2. Java 中線程的常用方法介紹 Java語言對(duì)線程的支持

主要體現(xiàn)在Thread類Runnable接口上,都繼承于java.lang包。它們都有個(gè)共同的方法:public void run()

  run方法為我們提供了線程實(shí)際工作執(zhí)行的代碼。

下表列出了Thread類的一些重要方法:

序號(hào) 方法描述
1 public void start()使該線程開始執(zhí)行;Java 虛擬機(jī)調(diào)用該線程的 run 方法。
2 public void run()如果該線程是使用獨(dú)立的 Runnable 運(yùn)行對(duì)象構(gòu)造的,則調(diào)用該 Runnable 對(duì)象的 run 方法;否則,該方法不執(zhí)行任何操作并返回。
3 public final void setName(String name)改變線程名稱,使之與參數(shù) name 相同。
4 public final void setPriority(int priority)更改線程的優(yōu)先級(jí)。
5 public final void setDaemon(boolean on)將該線程標(biāo)記為守護(hù)線程或用戶線程。
6 public final void join(long millisec)等待該線程終止的時(shí)間最長(zhǎng)為 millis 毫秒。
7 public void interrupt()中斷線程。
8 public final boolean isAlive()測(cè)試線程是否處于活動(dòng)狀態(tài)。

測(cè)試線程是否處于活動(dòng)狀態(tài)。 上述方法是被Thread對(duì)象調(diào)用的。下面的方法是Thread類的靜態(tài)方法。

序號(hào) 方法描述
1 public static void yield()暫停當(dāng)前正在執(zhí)行的線程對(duì)象,并執(zhí)行其他線程。
2 public static void sleep(long millisec)在指定的毫秒數(shù)內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠(暫停執(zhí)行),此操作受到系統(tǒng)計(jì)時(shí)器和調(diào)度程序精度和準(zhǔn)確性的影響。
3 public static boolean holdsLock(Object x)當(dāng)且僅當(dāng)當(dāng)前線程在指定的對(duì)象上保持監(jiān)視器鎖時(shí),才返回 true。
4 public static Thread currentThread()返回對(duì)當(dāng)前正在執(zhí)行的線程對(duì)象的引用。
5 public static void dumpStack()將當(dāng)前線程的堆棧跟蹤打印至標(biāo)準(zhǔn)錯(cuò)誤流。
Thread常用的方法

3. 線程初體驗(yàn)(編碼示例)

創(chuàng)建線程的方法有兩種:

1.繼承Thread類本身

2.實(shí)現(xiàn)Runnable接口

線程中的方法比較有特點(diǎn),比如:啟動(dòng)(start),休眠(sleep),停止等,多個(gè)線程是交互執(zhí)行的(cpu在某個(gè)時(shí)刻。只能執(zhí)行一個(gè)線程,當(dāng)一個(gè)線程休眠了或者執(zhí)行完畢了,另一個(gè)線程才能占用cpu來執(zhí)行)因?yàn)檫@是cpu的結(jié)構(gòu)來決定的,在某個(gè)時(shí)刻cpu只能執(zhí)行一個(gè)線程,不過速度相當(dāng)快,對(duì)于人來將可以認(rèn)為是并行執(zhí)行的。

在一個(gè)java文件中,可以有多個(gè)類(此處說的是外部類),但只能有一個(gè)public類。

這兩種創(chuàng)建線程的方法本質(zhì)沒有任何的不同,一個(gè)是實(shí)現(xiàn)Runnable接口,一個(gè)是繼承Thread類。

使用實(shí)現(xiàn)Runnable接口這種方法:

  1.可以避免java的單繼承的特性帶來的局限性;

  2.適合多個(gè)相同程序的代碼去處理同一個(gè)資源情況,把線程同程序的代碼及數(shù)據(jù)有效的分離,較好的體現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)思想。開發(fā)中大多數(shù)情況下都使用實(shí)現(xiàn)Runnable接口這種方法創(chuàng)建線程。

實(shí)現(xiàn)Runnable接口創(chuàng)建的線程最終還是要通過將自身實(shí)例作為參數(shù)傳遞給Thread然后執(zhí)行

語法: Thread actress=new Thread(Runnable target ,String name);

例如:

Thread actressThread=new Thread(new Actress(),"Ms.runnable");
actressThread.start();

代碼示例:

package com.study.thread;

public class Actor extends Thread{
    public void run() {
        System.out.println(getName() + "是一個(gè)演員!");
        int count = 0;
        boolean keepRunning = true;

        while(keepRunning){
            System.out.println(getName()+"登臺(tái)演出:"+ (++count));
            if(count == 100){
                keepRunning = false;
            }
            if(count%10== 0){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println(getName() + "的演出結(jié)束了!");
    }

    public static void main(String[] args) {
       Thread actor = new Actor();//向上轉(zhuǎn)型:子類轉(zhuǎn)型為父類,子類對(duì)象就會(huì)遺失和父類不同的方法。向上轉(zhuǎn)型符合Java提倡的面向抽象編程思想,還可以減輕編程工作量
       actor.setName("Mr. Thread");
       actor.start();
       
       //調(diào)用Thread的構(gòu)造函數(shù)Thread(Runnable target, String name)
       Thread actressThread = new Thread(new Actress(), "Ms. Runnable");
       actressThread.start();
    }

}
//注意:在“xx.java”文件中可以有多個(gè)類,但是只能有一個(gè)Public類。這里所說的不是內(nèi)部類,都是一個(gè)個(gè)獨(dú)立的外部類
class Actress implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "是一個(gè)演員!");//Runnable沒有g(shù)etName()方法,需要通過線程的currentThread()方法獲得線程名稱
        int count = 0;
        boolean keepRunning = true;

        while(keepRunning){
            System.out.println(Thread.currentThread().getName()+"登臺(tái)演出:"+ (++count));
            if(count == 100){
                keepRunning = false;
            }
            if(count%10== 0){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println(Thread.currentThread().getName() + "的演出結(jié)束了!");
    }
    
}

/**
 *運(yùn)行結(jié)果Mr. Thread線程和Ms. Runnable線程是交替執(zhí)行的情況
 *分析:計(jì)算機(jī)CPU處理器在同一時(shí)間同一個(gè)處理器同一個(gè)核只能運(yùn)行一條線程,
 *當(dāng)一條線程休眠之后,另外一個(gè)線程才獲得處理器時(shí)間
 */

運(yùn)行結(jié)果:

示例2:

ArmyRunnable 類:

package com.study.threadTest1;

/**
 * 軍隊(duì)線程
 * 模擬作戰(zhàn)雙方的行為
 */
public class ArmyRunnable implements Runnable {

    /* volatile關(guān)鍵字
     * volatile保證了線程可以正確的讀取其他線程寫入的值
     * 如果不寫成volatile,由于可見性的問題,當(dāng)前線程有可能不能讀到這個(gè)值
     * 關(guān)于可見性的問題可以參考JMM(Java內(nèi)存模型),里面講述了:happens-before原則、可見性
     * 用volatile修飾的變量,線程在每次使用變量的時(shí)候,都會(huì)讀取變量修改后的值
     */
    volatile boolean keepRunning = true;

    @Override
    public void run() {
        while (keepRunning) {
            //發(fā)動(dòng)5連擊
            for(int i=0;i<5;i++){
                System.out.println(Thread.currentThread().getName()+"進(jìn)攻對(duì)方["+i+"]");
                //讓出了處理器時(shí)間,下次該誰進(jìn)攻還不一定呢!
                Thread.yield();//yield()當(dāng)前運(yùn)行線程釋放處理器資源
            } 
        }
        System.out.println(Thread.currentThread().getName()+"結(jié)束了戰(zhàn)斗!");
    }

}

KeyPersonThread 類:

package com.study.threadTest1;


public class KeyPersonThread extends Thread {
    public void run(){
        System.out.println(Thread.currentThread().getName()+"開始了戰(zhàn)斗!");
        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"左突右殺,攻擊隋軍...");
        }
        System.out.println(Thread.currentThread().getName()+"結(jié)束了戰(zhàn)斗!");
    }

}

Stage 類:

package com.study.threadTest1;

/**
 * 隋唐演義大戲舞臺(tái) 6  */
public class Stage extends Thread {
    public void run(){
        System.out.println("歡迎觀看隋唐演義");
        //讓觀眾們安靜片刻,等待大戲上演
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        System.out.println("大幕徐徐拉開");

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

        System.out.println("話說隋朝末年,隋軍與農(nóng)民起義軍殺得昏天黑地...");
        ArmyRunnable armyTaskOfSuiDynasty = new ArmyRunnable();
        ArmyRunnable armyTaskOfRevolt = new ArmyRunnable();

        //使用Runnable接口創(chuàng)建線程
        Thread  armyOfSuiDynasty = new Thread(armyTaskOfSuiDynasty,"隋軍");
        Thread  armyOfRevolt = new Thread(armyTaskOfRevolt,"農(nóng)民起義軍");

        //啟動(dòng)線程,讓軍隊(duì)開始作戰(zhàn)
        armyOfSuiDynasty.start();
        armyOfRevolt.start();

        //舞臺(tái)線程休眠,大家專心觀看軍隊(duì)廝殺
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("正當(dāng)雙方激戰(zhàn)正酣,半路殺出了個(gè)程咬金");

        Thread  mrCheng = new KeyPersonThread();
        mrCheng.setName("程咬金");
        System.out.println("程咬金的理想就是結(jié)束戰(zhàn)爭(zhēng),使百姓安居樂業(yè)!");

        //停止軍隊(duì)作戰(zhàn)
        //停止線程的方法
        armyTaskOfSuiDynasty.keepRunning = false;
        armyTaskOfRevolt.keepRunning = false;

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        /*
         * 歷史大戲留給關(guān)鍵人物
         */
        mrCheng.start();

        //萬眾矚目,所有線程等待程先生完成歷史使命
        try {
            mrCheng.join();//join()使其他線程等待當(dāng)前線程終止
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("戰(zhàn)爭(zhēng)結(jié)束,人民安居樂業(yè),程先生實(shí)現(xiàn)了積極的人生夢(mèng)想,為人民作出了貢獻(xiàn)!");
        System.out.println("謝謝觀看隋唐演義,再見!");
    }

    public static void main(String[] args) {
        new Stage().start();
    }

}

運(yùn)行結(jié)果:

4. Java 線程的正確停止

如何正確的停止Java中的線程?

stop方法:該方法使線程戛然而止(突然停止),完成了哪些工作,哪些工作還沒有做都不清楚,且清理工作也沒有做。

stop方法不是正確的停止線程方法。線程停止不推薦使用stop方法。

正確的方法---設(shè)置退出標(biāo)志

使用volatile 定義boolean running=true,通過設(shè)置標(biāo)志變量running,來結(jié)束線程。

如本文:volatile boolean keepRunning=true;

這樣做的好處是:使得線程有機(jī)會(huì)使得一個(gè)完整的業(yè)務(wù)步驟被完整地執(zhí)行,在執(zhí)行完業(yè)務(wù)步驟后有充分的時(shí)間去做代碼的清理工作,使得線程代碼在實(shí)際中更安全。

廣為流傳的錯(cuò)誤方法---interrupt方法


當(dāng)一個(gè)線程運(yùn)行時(shí),另一個(gè)線程可以調(diào)用對(duì)應(yīng)的 Thread 對(duì)象的 interrupt()方法來中斷它,該方法只是在目標(biāo)線程中設(shè)置一個(gè)標(biāo)志,表示它已經(jīng)被中斷,并立即返回。這里需要注意的是,如果只是單純的調(diào)用 interrupt()方法,線程并沒有實(shí)際被中斷,會(huì)繼續(xù)往下執(zhí)行。

代碼示例:

package com.study.threadStop;

/**
 * 錯(cuò)誤終止進(jìn)程的方式——interrupt
 */
public class WrongWayStopThread extends Thread {

    public static void main(String[] args) {
        WrongWayStopThread thread = new WrongWayStopThread();
        System.out.println("Start Thread...");
        thread.start();
        
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Interrupting thread...");
        thread.interrupt();
        
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Stopping application...");
    }
    
    public void run() {
        while(true){
            System.out.println("Thread is running...");
            long time = System.currentTimeMillis();
            while ((System.currentTimeMillis()-time) <1000) {//這部分的作用大致相當(dāng)于Thread.sleep(1000),注意此處為什么沒有使用休眠的方法
                //減少屏幕輸出的空循環(huán)(使得每秒鐘只輸出一行信息)
            }
        }
    }
}

運(yùn)行結(jié)果:

由結(jié)果看到interrupt()方法并沒有使線程中斷,線程還是會(huì)繼續(xù)往下執(zhí)行。

Java API中介紹:

但是interrupt()方法可以使我們的中斷狀態(tài)發(fā)生改變,可以調(diào)用isInterrupted 方法

將上處run方法代碼改為下面一樣,程序就可以正常結(jié)束了。

public void run() {
        while(!this.isInterrupted()){//interrupt()可以使中斷狀態(tài)放生改變,調(diào)用isInterrupted()
            System.out.println("Thread is running...");
            long time = System.currentTimeMillis();
            while ((System.currentTimeMillis()-time) <1000) {//這部分的作用大致相當(dāng)于Thread.sleep(1000),注意此處為什么沒有使用休眠的方法
                //減少屏幕輸出的空循環(huán)(使得每秒鐘只輸出一行信息)
            }
        }
    }

但是這種所使用的退出方法實(shí)質(zhì)上還是前面說的使用退出旗標(biāo)的方法,不過這里所使用的退出旗標(biāo)是一個(gè)特殊的標(biāo)志“線程是否被中斷的狀態(tài)”。

這部分代碼相當(dāng)于線程休眠1秒鐘的代碼。但是為什么沒有使用Thread.sleep(1000)。如果采用這種方法就會(huì)出現(xiàn)

線程沒有正常結(jié)束,而且還拋出了一個(gè)異常,異常拋出位置在調(diào)用interrupt方法之后。為什么會(huì)有這種結(jié)果?

在API文檔中說過:如果線程由于調(diào)用的某些方法(比如sleep,join。。。)而進(jìn)入一種阻塞狀態(tài)時(shí),此時(shí)如果這個(gè)線程再被調(diào)用interrupt方法,它會(huì)產(chǎn)生兩個(gè)結(jié)果:第一,它的中斷狀態(tài)被清除clear,而不是被設(shè)置set。那isInterrupted 就不能返回是否被中斷的正確狀態(tài),那while函數(shù)就不能正確的退出。第二,sleep方法會(huì)收到InterruptedException被中斷。

interrupt()方法只能設(shè)置interrupt標(biāo)志位(且在線程阻塞情況下,標(biāo)志位會(huì)被清除,更無法設(shè)置中斷標(biāo)志位),無法停止線程

5. 線程交互

爭(zhēng)用條件:

1、當(dāng)多個(gè)線程同時(shí)共享訪問同一數(shù)據(jù)(內(nèi)存區(qū)域)時(shí),每個(gè)線程都嘗試操作該數(shù)據(jù),從而導(dǎo)致數(shù)據(jù)被破壞(corrupted),這種現(xiàn)象稱為爭(zhēng)用條件

2、原因是,每個(gè)線程在操作數(shù)據(jù)時(shí),會(huì)先將數(shù)據(jù)初值讀【取到自己獲得的內(nèi)存中】,然后在內(nèi)存中進(jìn)行運(yùn)算后,重新賦值到數(shù)據(jù)。

3、爭(zhēng)用條件:線程1在還【未重新將值賦回去時(shí)】,線程1阻塞,線程2開始訪問該數(shù)據(jù),然后進(jìn)行了修改,之后被阻塞的線程1再獲得資源,而將之前計(jì)算的值覆蓋掉線程2所修改的值,就出現(xiàn)了數(shù)據(jù)丟失情況。

互斥與同步:守恒的能量

1、線程的特點(diǎn),共享同一進(jìn)程的資源,同一時(shí)刻只能有一個(gè)線程占用CPU

2、由于線程有如上的特點(diǎn),所以就會(huì)存在多個(gè)線程爭(zhēng)搶資源的現(xiàn)象,就會(huì)存在爭(zhēng)用條件這種現(xiàn)象

3、為了讓線程能夠正確的運(yùn)行,不破壞共享的數(shù)據(jù),所以,就產(chǎn)生了同步和互斥的兩種線程運(yùn)行的機(jī)制

4、線程的互斥(加鎖實(shí)現(xiàn)):線程的運(yùn)行隔離開來,互不影響,使用synchronized關(guān)鍵字實(shí)現(xiàn)互斥行為,此關(guān)鍵字即可以出現(xiàn)在方法體之上也可以出現(xiàn)在方法體內(nèi),以一種塊的形式出現(xiàn),在此代碼塊中有線程的等待和喚醒動(dòng)作,用于支持線程的同步控制

5、線程的同步(線程的等待和喚醒:wait()+notifyAll()):線程的運(yùn)行有相互的通信控制,運(yùn)行完一個(gè)再正確的運(yùn)行另一個(gè)

6、鎖的概念:比如private final Object lockObj=new Object();

7、互斥實(shí)現(xiàn)方式:synchronized關(guān)鍵字

synchronized(lockObj){---執(zhí)行代碼----}加鎖操作

lockObj.wait();線程進(jìn)入等待狀態(tài),以避免線程持續(xù)申請(qǐng)鎖,而不去競(jìng)爭(zhēng)cpu資源

lockObj.notifyAll();喚醒所有l(wèi)ockObj對(duì)象上等待的線程

8、加鎖操作會(huì)開銷系統(tǒng)資源,降低效率

同步問題提出

線程的同步是為了防止多個(gè)線程訪問一個(gè)數(shù)據(jù)對(duì)象時(shí),對(duì)數(shù)據(jù)造成的破壞。
例如:兩個(gè)線程ThreadA、ThreadB都操作同一個(gè)對(duì)象Foo對(duì)象,并修改Foo對(duì)象上的數(shù)據(jù)。

public class Foo { 
    private int x = 100; 

    public int getX() { 
        return x; 
    } 

    public int fix(int y) { 
        x = x - y; 
        return x; 
    } 
}
public class MyRunnable implements Runnable { 
    private Foo foo = new Foo(); 

    public static void main(String[] args) { 
        MyRunnable r = new MyRunnable(); 
        Thread ta = new Thread(r, "Thread-A"); 
        Thread tb = new Thread(r, "Thread-B"); 
        ta.start(); 
        tb.start(); 
    } 

    public void run() { 
        for (int i = 0; i < 3; i++) { 
            this.fix(30); 
            try { 
                Thread.sleep(1); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            System.out.println(Thread.currentThread().getName() + " : 當(dāng)前foo對(duì)象的x值= " + foo.getX()); 
        } 
    } 

    public int fix(int y) { 
        return foo.fix(y); 
    } 
}

運(yùn)行結(jié)果:

Thread-A : 當(dāng)前foo對(duì)象的x值= 40 
Thread-B : 當(dāng)前foo對(duì)象的x值= 40 
Thread-B : 當(dāng)前foo對(duì)象的x值= -20 
Thread-A : 當(dāng)前foo對(duì)象的x值= -50 
Thread-A : 當(dāng)前foo對(duì)象的x值= -80 
Thread-B : 當(dāng)前foo對(duì)象的x值= -80 

Process finished with exit code 0

從結(jié)果發(fā)現(xiàn),這樣的輸出值明顯是不合理的。原因是兩個(gè)線程不加控制的訪問Foo對(duì)象并修改其數(shù)據(jù)所致。

如果要保持結(jié)果的合理性,只需要達(dá)到一個(gè)目的,就是將對(duì)Foo的訪問加以限制,每次只能有一個(gè)線程在訪問。這樣就能保證Foo對(duì)象中數(shù)據(jù)的合理性了。

在具體的Java代碼中需要完成一下兩個(gè)操作:
把競(jìng)爭(zhēng)訪問的資源類Foo變量x標(biāo)識(shí)為private;
同步哪些修改變量的代碼,使用synchronized關(guān)鍵字同步方法或代碼。

同步和鎖定

1、鎖的原理

Java中每個(gè)對(duì)象都有一個(gè)內(nèi)置鎖
當(dāng)程序運(yùn)行到非靜態(tài)的synchronized同步方法上時(shí),自動(dòng)獲得與正在執(zhí)行代碼類的當(dāng)前實(shí)例(this實(shí)例)有關(guān)的鎖。獲得一個(gè)對(duì)象的鎖也稱為獲取鎖、鎖定對(duì)象、在對(duì)象上鎖定或在對(duì)象上同步。
當(dāng)程序運(yùn)行到synchronized同步方法或代碼塊時(shí)才該對(duì)象鎖才起作用。
一個(gè)對(duì)象只有一個(gè)鎖。所以,如果一個(gè)線程獲得該鎖,就沒有其他線程可以獲得鎖,直到第一個(gè)線程釋放(或返回)鎖。這也意味著任何其他線程都不能進(jìn)入該對(duì)象上的synchronized方法或代碼塊,直到該鎖被釋放。
釋放鎖是指持鎖線程退出了synchronized同步方法或代碼塊。

關(guān)于鎖和同步,有一下幾個(gè)要點(diǎn):

1)、只能同步方法,而不能同步變量和類;

2)、每個(gè)對(duì)象只有一個(gè)鎖;當(dāng)提到同步時(shí),應(yīng)該清楚在什么上同步?也就是說,在哪個(gè)對(duì)象上同步?

3)、不必同步類中所有的方法,類可以同時(shí)擁有同步和非同步方法。

4)、如果兩個(gè)線程要執(zhí)行一個(gè)類中的synchronized方法,并且兩個(gè)線程使用相同的實(shí)例來調(diào)用方法,那么一次只能有一個(gè)線程能夠執(zhí)行方法,另一個(gè)需要等待,直到鎖被釋放。也就是說:如果一個(gè)線程在對(duì)象上獲得一個(gè)鎖,就沒有任何其他線程可以進(jìn)入(該對(duì)象的)類中的任何一個(gè)同步方法。

5)、如果線程擁有同步和非同步方法,則非同步方法可以被多個(gè)線程自由訪問而不受鎖的限制。

6)、線程睡眠時(shí),它所持的任何鎖都不會(huì)釋放。

7)、線程可以獲得多個(gè)鎖。比如,在一個(gè)對(duì)象的同步方法里面調(diào)用另外一個(gè)對(duì)象的同步方法,則獲取了兩個(gè)對(duì)象的同步鎖。

8)、同步損害并發(fā)性,應(yīng)該盡可能縮小同步范圍。同步不但可以同步整個(gè)方法,還可以同步方法中一部分代碼塊。

9)、在使用同步代碼塊時(shí)候,應(yīng)該指定在哪個(gè)對(duì)象上同步,也就是說要獲取哪個(gè)對(duì)象的鎖。例如:

public int fix(int y) {
        synchronized (this) {
            x = x - y;
        }
        return x;
    }

當(dāng)然,同步方法也可以改寫為非同步方法,但功能完全一樣的,例如:

 public synchronized int getX() {
        return x++;
    }

 public int getX() {
        synchronized (this) {
            return x;
        }
    }

效果是完全一樣的。

靜態(tài)方法同步

要同步靜態(tài)方法,需要一個(gè)用于整個(gè)類對(duì)象的鎖,這個(gè)對(duì)象是就是這個(gè)類(XXX.class)。
例如:

public static synchronized int setName(String name){
      Xxx.name = name;
}

等價(jià)于

public static int setName(String name){
      synchronized(Xxx.class){
            Xxx.name = name;
      }
}
線程同步小結(jié)

1、線程同步的目的是為了保護(hù)多個(gè)線程訪問一個(gè)資源時(shí)對(duì)資源的破壞。

2、線程同步方法是通過鎖來實(shí)現(xiàn),每個(gè)對(duì)象都有切僅有一個(gè)鎖,這個(gè)鎖與一個(gè)特定的對(duì)象關(guān)聯(lián),線程一旦獲取了對(duì)象鎖,其他訪問該對(duì)象的線程就無法再訪問該對(duì)象的其他同步方法。

3、對(duì)于靜態(tài)同步方法,鎖是針對(duì)這個(gè)類的,鎖對(duì)象是該類的Class對(duì)象。靜態(tài)和非靜態(tài)方法的鎖互不干預(yù)。一個(gè)線程獲得鎖,當(dāng)在一個(gè)同步方法中訪問另外對(duì)象上的同步方法時(shí),會(huì)獲取這兩個(gè)對(duì)象鎖。

4、對(duì)于同步,要時(shí)刻清醒在哪個(gè)對(duì)象上同步,這是關(guān)鍵。

5、編寫線程安全的類,需要時(shí)刻注意對(duì)多個(gè)線程競(jìng)爭(zhēng)訪問資源的邏輯和安全做出正確的判斷,對(duì)“原子”操作做出分析,并保證原子操作期間別的線程無法訪問競(jìng)爭(zhēng)資源。

6、當(dāng)多個(gè)線程等待一個(gè)對(duì)象鎖時(shí),沒有獲取到鎖的線程將發(fā)生阻塞。

7、死鎖是線程間相互等待鎖鎖造成的,在實(shí)際中發(fā)生的概率非常的小。真讓你寫個(gè)死鎖程序,不一定好使,呵呵。但是,一旦程序發(fā)生死鎖,程序?qū)⑺赖簟?/p> 深入剖析互斥與同步

互斥的實(shí)現(xiàn)(加鎖):synchronized(lockObj); 保證的同一時(shí)間,只有一個(gè)線程獲得lockObj.

同步的實(shí)現(xiàn):wait()/notify()/notifyAll()

注意: wait()、notify()、notifyAll()方法均屬于Object對(duì)象,而不是Thread對(duì)象。

void notify()

喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程。

void notifyAll()

喚醒在此對(duì)象監(jiān)視器上等待的所有線程。

void wait()

導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法。

當(dāng)然,wait()還有另外兩個(gè)重載方法:

void wait(long timeout)

導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法,或者超過指定的時(shí)間量。

void wait(long timeout, int nanos)
導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法,或者其他某個(gè)線程中斷當(dāng)前線程,或者已超過某個(gè)實(shí)際時(shí)間量。

notify()喚醒wait set中的一條線程,而notifyall()喚醒所有線程。

同步是兩個(gè)線程之間的一種交互的操作(一個(gè)線程發(fā)出消息另外一個(gè)線程響應(yīng))
關(guān)于等待/通知,要記住的關(guān)鍵點(diǎn)是:
必須從同步環(huán)境內(nèi)調(diào)用wait()、notify()、notifyAll()方法。線程不能調(diào)用對(duì)象上等待或通知的方法,除非它擁有那個(gè)對(duì)象的鎖。
wait()、notify()、notifyAll()都是Object的實(shí)例方法。與每個(gè)對(duì)象具有鎖一樣,每個(gè)對(duì)象可以有一個(gè)線程列表,他們等待來自該信號(hào)(通知)。線程通過執(zhí)行對(duì)象上的wait()方法獲得這個(gè)等待列表。從那時(shí)候起,它不再執(zhí)行任何其他指令,直到調(diào)用對(duì)象的notify()方法為止。如果多個(gè)線程在同一個(gè)對(duì)象上等待,則將只選擇一個(gè)線程(不保證以何種順序)繼續(xù)執(zhí)行。如果沒有線程等待,則不采取任何特殊操作。
下面看個(gè)例子就明白了:

/** 
* 計(jì)算輸出其他線程鎖計(jì)算的數(shù)據(jù) 
*/ 
public class ThreadA { 
    public static void main(String[] args) { 
        ThreadB b = new ThreadB(); 
        //啟動(dòng)計(jì)算線程 
        b.start(); 
        //線程A擁有b對(duì)象上的鎖。線程為了調(diào)用wait()或notify()方法,該線程必須是那個(gè)對(duì)象鎖的擁有者 
        synchronized (b) { 
            try { 
                System.out.println("等待對(duì)象b完成計(jì)算。。。"); 
                //當(dāng)前線程A等待 
                b.wait(); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            System.out.println("b對(duì)象計(jì)算的總和是:" + b.total); 
        } 
    } 
}
/** 
* 計(jì)算1+2+3 ... +100的和 
*/ 
public class ThreadB extends Thread { 
    int total; 

    public void run() { 
        synchronized (this) { 
            for (int i = 0; i < 101; i++) { 
                total += i; 
            } 
            //(完成計(jì)算了)喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程,在本例中線程A被喚醒 
            notify(); 
        } 
    } 
}
結(jié)果:
等待對(duì)象b完成計(jì)算。。。
b對(duì)象計(jì)算的總和是:5050
Process finished with exit code 0

千萬注意:
當(dāng)在對(duì)象上調(diào)用wait()方法時(shí),執(zhí)行該代碼的線程立即放棄它在對(duì)象上的鎖。然而調(diào)用notify()時(shí),并不意味著這時(shí)線程會(huì)放棄其鎖。如果線程榮然在完成同步代碼,則線程在移出之前不會(huì)放棄鎖。因此,只要調(diào)用notify()并不意味著這時(shí)該鎖變得可用。

多個(gè)線程在等待一個(gè)對(duì)象鎖時(shí)候使用notifyAll():
在多數(shù)情況下,最好通知等待某個(gè)對(duì)象的所有線程。如果這樣做,可以在對(duì)象上使用notifyAll()讓所有在此對(duì)象上等待的線程沖出等待區(qū),返回到可運(yùn)行狀態(tài)。

如何理解同步:Wait Set

Critical Section(臨界資源)Wait Set(等待區(qū)域)

wait set 類似于線程的休息室,訪問共享數(shù)據(jù)的代碼稱為critical section。一個(gè)線程獲取鎖,然后進(jìn)入臨界區(qū),發(fā)現(xiàn)某些條件不滿足,然后調(diào)用鎖對(duì)象上的wait方法,然后線程釋放掉鎖資源,進(jìn)入鎖對(duì)象上的wait set。由于線程釋放釋放了理解資源,其他線程可以獲取所資源,然后執(zhí)行,完了以后調(diào)用notify,通知鎖對(duì)象上的等待線程。

Ps:若調(diào)用notify();則隨機(jī)拿出(這隨機(jī)拿出是內(nèi)部的算法,無需了解)一條在等待的資源進(jìn)行準(zhǔn)備進(jìn)入Critical Section;若調(diào)用notifyAll();則全部取出進(jìn)行準(zhǔn)備進(jìn)入Critical Section。

6. 總結(jié)與展望



擴(kuò)展建議:如何擴(kuò)展Java并發(fā)知識(shí)

1、Java Memory Mode : JMM描述了java線程如何通過內(nèi)存進(jìn)行交互,了解happens-before , synchronized,voliatile & final

2、Locks % Condition:Java鎖機(jī)制和等待條件的高層實(shí)現(xiàn) java.util,concurrent.locks

3、線程安全性:原子性與可見性, java.util.concurrent.atomic synchronized(鎖的方法塊)&volatile(定義公共資源) DeadLocks(死鎖)--了解什么是死鎖,死鎖產(chǎn)生的條件

4、多線程編程常用的交互模型

· Producer-Consumer模型(生產(chǎn)者-消費(fèi)者模型)

· Read-Write Lock模型(讀寫鎖模型)

· Future模型

· Worker Thread模型

考慮在Java并發(fā)實(shí)現(xiàn)當(dāng)中,有哪些類實(shí)現(xiàn)了這些模型,供我們直接調(diào)用

5、Java5中并發(fā)編程工具:java.util.concurrent 包下的

例如:線程池ExcutorService 、Callable&Future 、BlockingQueue

6、推薦書本:CoreJava 、JavaConcurrency In Practice

出處:http://www.cnblogs.com/Qian12...

文章有不當(dāng)之處,歡迎指正,你也可以關(guān)注我的微信公眾號(hào):好好學(xué)java,獲取優(yōu)質(zhì)學(xué)習(xí)資源。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/69479.html

相關(guān)文章

  • Java開發(fā)

    摘要:大多數(shù)待遇豐厚的開發(fā)職位都要求開發(fā)者精通多線程技術(shù)并且有豐富的程序開發(fā)調(diào)試優(yōu)化經(jīng)驗(yàn),所以線程相關(guān)的問題在面試中經(jīng)常會(huì)被提到。將對(duì)象編碼為字節(jié)流稱之為序列化,反之將字節(jié)流重建成對(duì)象稱之為反序列化。 JVM 內(nèi)存溢出實(shí)例 - 實(shí)戰(zhàn) JVM(二) 介紹 JVM 內(nèi)存溢出產(chǎn)生情況分析 Java - 注解詳解 詳細(xì)介紹 Java 注解的使用,有利于學(xué)習(xí)編譯時(shí)注解 Java 程序員快速上手 Kot...

    LuDongWei 評(píng)論0 收藏0
  • Java核心技術(shù)教程整理,長(zhǎng)期更新

    以下是Java技術(shù)棧微信公眾號(hào)發(fā)布的關(guān)于 Java 的技術(shù)干貨,從以下幾個(gè)方面匯總。 Java 基礎(chǔ)篇 Java 集合篇 Java 多線程篇 Java JVM篇 Java 進(jìn)階篇 Java 新特性篇 Java 工具篇 Java 書籍篇 Java基礎(chǔ)篇 8張圖帶你輕松溫習(xí) Java 知識(shí) Java父類強(qiáng)制轉(zhuǎn)換子類原則 一張圖搞清楚 Java 異常機(jī)制 通用唯一標(biāo)識(shí)碼UUID的介紹及使用 字符串...

    Anchorer 評(píng)論0 收藏0
  • java 基礎(chǔ) - 收藏集 - 掘金

    摘要:基礎(chǔ)知識(shí)復(fù)習(xí)后端掘金的作用表示靜態(tài)修飾符,使用修飾的變量,在中分配內(nèi)存后一直存在,直到程序退出才釋放空間。將對(duì)象編碼為字節(jié)流稱之為序列化,反之將字節(jié)流重建成對(duì)象稱之為反序列化。 Java 學(xué)習(xí)過程|完整思維導(dǎo)圖 - 后端 - 掘金JVM 1. 內(nèi)存模型( 內(nèi)存分為幾部分? 堆溢出、棧溢出原因及實(shí)例?線上如何排查?) 2. 類加載機(jī)制 3. 垃圾回收 Java基礎(chǔ) 什么是接口?什么是抽象...

    makeFoxPlay 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<