成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Thread類源碼解讀(3)——線程中斷interrupt

fevin / 3530人閱讀

摘要:現(xiàn)在終止一個(gè)線程,基本上只能靠曲線救國(guó)式的中斷來(lái)實(shí)現(xiàn)。中斷機(jī)制的核心在于中斷狀態(tài)和異常中斷狀態(tài)設(shè)置一個(gè)中斷狀態(tài)清除一個(gè)中斷狀態(tài)方法同時(shí)會(huì)返回線程原來(lái)的中斷的狀態(tài)。中斷異常中斷異常一般是線程被中斷后,在一些類型的方法如中拋出。

前言

系列文章目錄

線程中斷是一個(gè)很重要的概念,通常,取消一個(gè)任務(wù)的執(zhí)行,最好的,同時(shí)也是最合理的方法,就是通過(guò)中斷。

本篇我們主要還是通過(guò)源碼分析來(lái)看看中斷的概念。

本文的源碼基于JDK1.8

Interrupt status & InterruptedException

java線程的中斷機(jī)制為我們提供了一個(gè)契機(jī),使被中斷的線程能夠有機(jī)會(huì)從當(dāng)前的任務(wù)中跳脫出來(lái)。而中斷機(jī)制的最核心的兩個(gè)概念就是interrupt statusInterruptedException

java中對(duì)于中斷的大部分操作無(wú)外乎以下兩點(diǎn):

設(shè)置或者清除中斷標(biāo)志位

拋出InterruptedException

interrupt status

在java中,每一個(gè)線程都有一個(gè)中斷標(biāo)志位,表征了當(dāng)前線程是否處于被中斷狀態(tài),我們可以把這個(gè)標(biāo)識(shí)位理解成一個(gè)boolean類型的變量,當(dāng)我們中斷一個(gè)線程時(shí),將該標(biāo)識(shí)位設(shè)為true,當(dāng)我們清除中斷狀態(tài)時(shí),將其設(shè)置為false, 其偽代碼如下:

(注意,本文的偽代碼部分是我個(gè)人所寫,并不權(quán)威,只是幫助我自己理解寫的)

// 注意,這是偽代碼?。?!
// 注意,這是偽代碼?。?!
// 注意,這是偽代碼?。?!
public class Thread implements Runnable {
    private boolean interruptFlag; // 中斷標(biāo)志位
    
    public boolean getInterruptFlag() {
        return this.interruptFlag;
    }
    
    public void setInterruptFlag(boolean flag) {
        this.interruptFlag = flag;
    }
}

然而,在Thread線程類里面,并沒有類似中斷標(biāo)志位的屬性,但是提供了獲取中斷標(biāo)志位的接口:

/**
 * Tests if some Thread has been interrupted.  The interrupted state
 * is reset or not based on the value of ClearInterrupted that is
 * passed.
 */
private native boolean isInterrupted(boolean ClearInterrupted);

這是一個(gè)native方法,同時(shí)也是一個(gè)private方法,該方法除了能夠返回當(dāng)前線程的中斷狀態(tài),還能根據(jù)ClearInterrupted參數(shù)來(lái)決定要不要重置中斷標(biāo)志位(reset操作相當(dāng)于上面的interruptFlag = false)。

Thread類提供了兩個(gè)public方法來(lái)使用該native方法:

public boolean isInterrupted() {
    return isInterrupted(false);
}

public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}

其中isInterrupted調(diào)用了isInterrupted(false), ClearInterrupted參數(shù)為false, 說(shuō)明它僅僅返回線程實(shí)例的中斷狀態(tài),但是不會(huì)對(duì)現(xiàn)有的中斷狀態(tài)做任何改變,偽代碼可以是:

// 注意,這是偽代碼?。?!
// 注意,這是偽代碼?。。?// 注意,這是偽代碼!??!
public boolean isInterrupted() {
    return interruptFlag; //直接返回Thread實(shí)例的中斷狀態(tài)
}

interrupted是一個(gè)靜態(tài)方法,所以它可以由Thread類直接調(diào)用,自然就是作用于當(dāng)前正在執(zhí)行的線程,所以函數(shù)內(nèi)部使用了currentThread()方法,與isInterrupted()方法不同的是,它的ClearInterrupted參數(shù)為true,在返回線程中斷狀態(tài)的同時(shí),重置了中斷標(biāo)識(shí)位,偽代碼可以是:

// 注意,這是偽代碼!??!
// 注意,這是偽代碼?。?!
// 注意,這是偽代碼!?。?public static boolean interrupted() {
    Thread current = Thread.currentThread(); // 獲取當(dāng)前正在執(zhí)行的線程
    boolean interruptFlag = current.getInterruptFlag(); // 獲取線程的中斷狀態(tài)
    current.setInterruptFlag(false); // 清除線程的中斷狀態(tài)
    return interruptFlag; //返回線程的中斷狀態(tài)
}

可見,isInterrupted()interrupted() 方法只涉及到中斷狀態(tài)的查詢,最多是多加一步重置中斷狀態(tài),并不牽涉到InterruptedException

不過(guò)值得一提的是,在我們能使用到的public方法中,interrupted()是我們清除中斷的唯一方法。

InterruptedException

我們直接來(lái)看的源碼:

/**
 * Thrown when a thread is waiting, sleeping, or otherwise occupied,
 * and the thread is interrupted, either before or during the activity.
 * Occasionally a method may wish to test whether the current
 * thread has been interrupted, and if so, to immediately throw
 * this exception.  The following code can be used to achieve
 * this effect:
 * 
 *  if (Thread.interrupted())  // Clears interrupted status!
 *      throw new InterruptedException();
 * 
* * @author Frank Yellin * @see java.lang.Object#wait() * @see java.lang.Object#wait(long) * @see java.lang.Object#wait(long, int) * @see java.lang.Thread#sleep(long) * @see java.lang.Thread#interrupt() * @see java.lang.Thread#interrupted() * @since JDK1.0 */ public class InterruptedException extends Exception { private static final long serialVersionUID = 6700697376100628473L; /** * Constructs an InterruptedException with no detail message. */ public InterruptedException() { super(); } /** * Constructs an InterruptedException with the * specified detail message. * * @param s the detail message. */ public InterruptedException(String s) { super(s); } }

上面的注釋是說(shuō),在線程處于“waiting, sleeping”甚至是正在運(yùn)行的過(guò)程中,如果被中斷了,就可以拋出該異常,我們先來(lái)回顧一下我們前面遇到過(guò)的拋出InterruptedException異常的例子:

(1) wait(long timeout)方法中的InterruptedException

/* 
 *
 * @param      timeout   the maximum time to wait in milliseconds.
 * @throws  IllegalArgumentException      if the value of timeout is
 *               negative.
 * @throws  IllegalMonitorStateException  if the current thread is not
 *               the owner of the object"s monitor.
 * @throws  InterruptedException if any thread interrupted the
 *             current thread before or while the current thread
 *             was waiting for a notification.  The interrupted
 *             status of the current thread is cleared when
 *             this exception is thrown.
 * @see        java.lang.Object#notify()
 * @see        java.lang.Object#notifyAll()
 */
public final native void wait(long timeout) throws InterruptedException;

該方法的注釋中提到,如果在有別的線程在當(dāng)前線程進(jìn)入waiting狀態(tài)之前或者已經(jīng)進(jìn)入waiting狀態(tài)之后中斷了當(dāng)前線程,該方法就會(huì)拋出InterruptedException,同時(shí),異常拋出后,當(dāng)前線程的中斷狀態(tài)也會(huì)被清除。

(2) sleep(long millis)方法中的InterruptedException

/* @param  millis
 *         the length of time to sleep in milliseconds
 *
 * @throws  IllegalArgumentException
 *          if the value of {@code millis} is negative
 *
 * @throws  InterruptedException
 *          if any thread has interrupted the current thread. The
 *          interrupted status of the current thread is
 *          cleared when this exception is thrown.
 */
public static native void sleep(long millis) throws InterruptedException;

與上面的wait方法一致,如果當(dāng)前線程被中斷了,sleep方法會(huì)拋出InterruptedException,并且清除中斷狀態(tài)。

如果有其他方法直接或間接的調(diào)用了這兩個(gè)方法,那他們自然也會(huì)在線程被中斷的時(shí)候拋出InterruptedException,并且清除中斷狀態(tài)。例如:

wait()

wait(long timeout, int nanos)

sleep(long millis, int nanos)

join()

join(long millis)

join(long millis, int nanos)

這里值得注意的是,雖然這些方法會(huì)拋出InterruptedException,但是并不會(huì)終止當(dāng)前線程的執(zhí)行,當(dāng)前線程可以選擇忽略這個(gè)異常。

也就是說(shuō),無(wú)論是設(shè)置interrupt status 還是拋出InterruptedException,它們都是給當(dāng)前線程的建議,當(dāng)前線程可以選擇采納或者不采納,它們并不會(huì)影響當(dāng)前線程的執(zhí)行。

至于在收到這些中斷的建議后,當(dāng)前線程要怎么處理,也完全取決于當(dāng)前線程。

interrupt

上面我們說(shuō)了怎么檢查(以及清除)一個(gè)線程的中斷狀態(tài),提到當(dāng)一個(gè)線程被中斷后,有一些方法會(huì)拋出InterruptedException。

下面我們就來(lái)看看怎么中斷一個(gè)線程。

要中斷一個(gè)線程,只需調(diào)用該線程的interrupt方法,其源碼如下:

/**
 * Interrupts this thread.
 *
 * 

Unless the current thread is interrupting itself, which is * always permitted, the {@link #checkAccess() checkAccess} method * of this thread is invoked, which may cause a {@link * SecurityException} to be thrown. * *

If this thread is blocked in an invocation of the {@link * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link * Object#wait(long, int) wait(long, int)} methods of the {@link Object} * class, or of the {@link #join()}, {@link #join(long)}, {@link * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)}, * methods of this class, then its interrupt status will be cleared and it * will receive an {@link InterruptedException}. * *

If this thread is blocked in an I/O operation upon an {@link * java.nio.channels.InterruptibleChannel InterruptibleChannel} * then the channel will be closed, the thread"s interrupt * status will be set, and the thread will receive a {@link * java.nio.channels.ClosedByInterruptException}. * *

If this thread is blocked in a {@link java.nio.channels.Selector} * then the thread"s interrupt status will be set and it will return * immediately from the selection operation, possibly with a non-zero * value, just as if the selector"s {@link * java.nio.channels.Selector#wakeup wakeup} method were invoked. * *

If none of the previous conditions hold then this thread"s interrupt * status will be set.

* *

Interrupting a thread that is not alive need not have any effect. * * @throws SecurityException * if the current thread cannot modify this thread * * @revised 6.0 * @spec JSR-51 */ public void interrupt() { if (this != Thread.currentThread()) checkAccess(); synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { interrupt0(); // Just to set the interrupt flag b.interrupt(this); return; } } interrupt0(); }

上面的注釋很長(zhǎng),我們一段一段來(lái)看:

/**
 * Interrupts this thread.
 *
 * 

Unless the current thread is interrupting itself, which is * always permitted, the {@link #checkAccess() checkAccess} method * of this thread is invoked, which may cause a {@link * SecurityException} to be thrown. ... */

上面這段首先說(shuō)明了這個(gè)函數(shù)的目的是中斷這個(gè)線程,這個(gè)this thread,當(dāng)然指的就是該方法所屬的線程對(duì)象所代表的線程。

接著說(shuō)明了,一個(gè)線程總是被允許中斷自己,但是我們?nèi)绻胍谝粋€(gè)線程中中斷另一個(gè)線程的執(zhí)行,就需要先通過(guò)checkAccess()檢查權(quán)限。這有可能拋出SecurityException異常, 這段話用代碼體現(xiàn)為:

if (this != Thread.currentThread())
    checkAccess();

我們接著往下看:

/*
 ...
 * 

If this thread is blocked in an invocation of the {@link * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link * Object#wait(long, int) wait(long, int)} methods of the {@link Object} * class, or of the {@link #join()}, {@link #join(long)}, {@link * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)}, * methods of this class, then its interrupt status will be cleared and it * will receive an {@link InterruptedException}. ... */

上面這段是說(shuō),如果線程因?yàn)橐韵路椒ǖ恼{(diào)用而處于阻塞中,那么(調(diào)用了interrupt方法之后),線程的中斷標(biāo)志會(huì)被清除,并且收到一個(gè)InterruptedException:

Object的方法

wait()

wait(long)

wait(long, int)

Thread的方法

join()

join(long)

join(long, int)

sleep(long)

sleep(long, int)

關(guān)于這一點(diǎn),我們上面在分析InterruptedException的時(shí)候已經(jīng)分析過(guò)了。

這里插一句,由于上面這些方法在拋出InterruptedException異常后,會(huì)同時(shí)清除中斷標(biāo)識(shí)位,因此當(dāng)我們此時(shí)不想或者無(wú)法傳遞InterruptedException異常,也不對(duì)該異常做任何處理時(shí),我們最好通過(guò)再次調(diào)用interrupt來(lái)恢復(fù)中斷的狀態(tài),以供上層調(diào)用者處理,這一點(diǎn),我們?cè)谥鹦蟹治鯝QS源碼(二): 鎖的釋放的最后就說(shuō)明過(guò)這種用法。

接下來(lái)的兩段注釋是關(guān)于NIO的,我們暫時(shí)不看,直接看最后兩段:

/*
 ...
 * 

If none of the previous conditions hold then this thread"s interrupt * status will be set.

* *

Interrupting a thread that is not alive need not have any effect. */

這段話是說(shuō):

如果線程沒有因?yàn)樯厦娴暮瘮?shù)調(diào)用而進(jìn)入阻塞狀態(tài)的話,那么中斷這個(gè)線程僅僅會(huì)設(shè)置它的中斷標(biāo)志位(而不會(huì)拋出InterruptedException)

中斷一個(gè)已經(jīng)終止的線程不會(huì)有任何影響。

注釋看完了之后我們?cè)賮?lái)看代碼部分,其實(shí)代碼部分很簡(jiǎn)單,中間那段同步代碼塊是和NIO有關(guān)的,我們可以暫時(shí)不管,整個(gè)方法的核心調(diào)用就是interrupt0()方法,而它是一個(gè)native方法:

private native void interrupt0();

這個(gè)方法所做的事情很簡(jiǎn)單:

Just to set the interrupt flag

所以,至此我們明白了,所謂“中斷一個(gè)線程”,其實(shí)并不是讓一個(gè)線程停止運(yùn)行,僅僅是將線程的中斷標(biāo)志設(shè)為true, 或者在某些特定情況下拋出一個(gè)InterruptedException,它并不會(huì)直接將一個(gè)線程停掉,在被中斷的線程的角度看來(lái),僅僅是自己的中斷標(biāo)志位被設(shè)為true了,或者自己所執(zhí)行的代碼中拋出了一個(gè)InterruptedException異常,僅此而已。

終止一個(gè)線程

既然上面我們提到了,中斷一個(gè)線程并不會(huì)使得該線程停止執(zhí)行,那么我們?cè)撛鯓咏K止一個(gè)線程的執(zhí)行呢。早期的java中提供了stop()方法來(lái)停止一個(gè)線程,但是這個(gè)方法是不安全的,所以已經(jīng)被廢棄了。現(xiàn)在終止一個(gè)線程,基本上只能靠“曲線救國(guó)”式的中斷來(lái)實(shí)現(xiàn)。

終止處于阻塞狀態(tài)的線程

前面我們說(shuō)過(guò),當(dāng)一個(gè)線程因?yàn)檎{(diào)用wait,sleep,join方法而進(jìn)入阻塞狀態(tài)后,若在這時(shí)中斷這個(gè)線程,則這些方法將會(huì)拋出InterruptedException異常,我們可以利用這個(gè)異常,使線程跳出阻塞狀態(tài),從而終止線程。

@Override
public void run() {
    while(true) {
        try {
            // do some task
            // blocked by calling wait/sleep/join
        } catch (InterruptedException ie) {  
            // 如果該線程被中斷,則會(huì)拋出InterruptedException異常
            // 我們通過(guò)捕獲這個(gè)異常,使得線程從block狀態(tài)退出
            break; // 這里使用break, 可以使我們?cè)诰€程中斷后退出死循環(huán),從而終止線程。
        }
    }
}
終止處于運(yùn)行狀態(tài)的線程

與中斷一個(gè)處于阻塞狀態(tài)所不同的是,中斷一個(gè)處于運(yùn)行狀態(tài)的線程只會(huì)將該線程的中斷標(biāo)志位設(shè)為true, 而并不會(huì)拋出InterruptedException異常,為了能在運(yùn)行過(guò)程中感知到線程已經(jīng)被中斷了,我們只能通過(guò)不斷地檢查中斷標(biāo)志位來(lái)實(shí)現(xiàn):

@Override
public void run() {
    while (!isInterrupted()) {
        // do some task...
    }
}

這里,我們每次循環(huán)都會(huì)先檢查中斷標(biāo)志位,只要當(dāng)前線程被中斷了,isInterrupted()方法就會(huì)返回true,從而終止循環(huán)。

終止一個(gè)Alive的線程

上面我們分別介紹了怎樣終止一個(gè)處于阻塞狀態(tài)或運(yùn)行狀態(tài)的線程,如果我們將這兩種方法結(jié)合起來(lái),那么就可以同時(shí)應(yīng)對(duì)這兩種狀況,從而能夠終止任意一個(gè)存活的線程:

@Override
public void run() {
    try {
        // 1. isInterrupted() 用于終止一個(gè)正在運(yùn)行的線程。
        while (!isInterrupted()) {
            // 執(zhí)行任務(wù)...
        }
    } catch (InterruptedException ie) {  
        // 2. InterruptedException異常用于終止一個(gè)處于阻塞狀態(tài)的線程
    }
}

不過(guò)使用這兩者的組合一定要注意,wait,sleep,join等方法拋出InterruptedException有一個(gè)副作用: 清除當(dāng)前的中斷標(biāo)志位,所以不要在異常拋出后不做任何處理,而寄望于用isInterrupted()方法來(lái)判斷,因?yàn)橹袠?biāo)志位已經(jīng)被重置了,所以下面這種寫法是不對(duì)的:

@Override
public void run() {
    //isInterrupted() 用于終止一個(gè)正在運(yùn)行的線程。
    while (!isInterrupted()) {
        try {
                // 執(zhí)行任務(wù)...
            }
        } catch (InterruptedException ie) {  
            // 在這里不做任何處理,僅僅依靠isInterrupted檢測(cè)異常
        }
    }
}

這個(gè)方法中,在catch塊中我們檢測(cè)到異常后沒有使用break方法跳出循環(huán),而此時(shí)中斷狀態(tài)已經(jīng)被重置,當(dāng)我們?cè)偃フ{(diào)用isInterrupted,依舊會(huì)返回false, 故線程仍然會(huì)在while循環(huán)中執(zhí)行,無(wú)法被中斷。

總結(jié)

Java沒有提供一種安全直接的方法來(lái)停止某個(gè)線程,但是提供了中斷機(jī)制。對(duì)于被中斷的線程,中斷只是一個(gè)建議,至于收到這個(gè)建議后線程要采取什么措施,完全由線程自己決定。

中斷機(jī)制的核心在于中斷狀態(tài)和InterruptedException異常

中斷狀態(tài):

設(shè)置一個(gè)中斷狀態(tài): Thread#interrupt

清除一個(gè)中斷狀態(tài): Thread.interrupted

Thread.interrupted方法同時(shí)會(huì)返回線程原來(lái)的中斷的狀態(tài)。
如果僅僅想查看線程當(dāng)前的中斷狀態(tài)而不清除原來(lái)的狀態(tài),則應(yīng)該使用Thread#isInterrupted。

某些阻塞方法在拋出InterruptedException異常后,會(huì)同時(shí)清除中斷狀態(tài)。若不能對(duì)該異常做出處理也無(wú)法向上層拋出,則應(yīng)該通過(guò)再次調(diào)用interrupt方法恢復(fù)中斷狀態(tài),以供上層處理,通常情況下我們都不應(yīng)該屏蔽中斷請(qǐng)求。

中斷異常:

中斷異常一般是線程被中斷后,在一些block類型的方法(如wait,sleep,join)中拋出。

我們可以使用Thread#interrupt中斷一個(gè)線程,被中斷的線程所受的影響為以下兩種之一:

若被中斷前,該線程處于非阻塞狀態(tài),那么該線程的中斷狀態(tài)被設(shè)為true, 除此之外,不會(huì)發(fā)生任何事。

若被中斷前,該線程處于阻塞狀態(tài)(調(diào)用了wait,sleep,join等方法),那么該線程將會(huì)立即從阻塞狀態(tài)中退出,并拋出一個(gè)InterruptedException異常,同時(shí),該線程的中斷狀態(tài)被設(shè)為false, 除此之外,不會(huì)發(fā)生任何事。

無(wú)論是中斷狀態(tài)的改變還是InterruptedException被拋出,這些都是當(dāng)前線程可以感知到的"建議",如果當(dāng)前線程選擇忽略這些建議(例如簡(jiǎn)單地catch住異常繼續(xù)執(zhí)行),那么中斷機(jī)制對(duì)于當(dāng)前線程就沒有任何影響,就好像什么也沒有發(fā)生一樣。

所以,中斷一個(gè)線程,只是傳遞了請(qǐng)求中斷的消息,并不會(huì)直接阻止一個(gè)線程的運(yùn)行。

(完)

查看更多系列文章:系列文章目錄

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/76808.html

相關(guān)文章

  • 逐行分析AQS源碼(2)——獨(dú)占鎖的釋放

    摘要:我們知道,這個(gè)函數(shù)將返回當(dāng)前正在執(zhí)行的線程的中斷狀態(tài),并清除它。注意,中斷對(duì)線程來(lái)說(shuō)只是一個(gè)建議,一個(gè)線程被中斷只是其中斷狀態(tài)被設(shè)為線程可以選擇忽略這個(gè)中斷,中斷一個(gè)線程并不會(huì)影響線程的執(zhí)行。 前言 系列文章目錄 上一篇文章 我們逐行分析了獨(dú)占鎖的獲取操作, 本篇文章我們來(lái)看看獨(dú)占鎖的釋放。如果前面的鎖的獲取流程你已經(jīng)趟過(guò)一遍了, 那鎖的釋放部分就很簡(jiǎn)單了, 這篇文章我們直接開始看...

    tinna 評(píng)論0 收藏0
  • 源碼的角度再學(xué)「Thread

    摘要:前言中的線程是使用類實(shí)現(xiàn)的,在初學(xué)的時(shí)候就學(xué)過(guò)了,也在實(shí)踐中用過(guò),不過(guò)一直沒從源碼的角度去看過(guò)它的實(shí)現(xiàn),今天從源碼的角度出發(fā),再次學(xué)習(xí),愿此后對(duì)的實(shí)踐更加得心應(yīng)手。如果一個(gè)線程已經(jīng)啟動(dòng)并且尚未死亡,則該線程處于活動(dòng)狀態(tài)。 showImg(https://segmentfault.com/img/remote/1460000017963014?w=1080&h=720); 前言 Java...

    abson 評(píng)論0 收藏0
  • Java Executors 源碼分析

    摘要:表示一個(gè)異步任務(wù)的結(jié)果,就是向線程池提交一個(gè)任務(wù)后,它會(huì)返回對(duì)應(yīng)的對(duì)象。它們分別提供兩個(gè)重要的功能阻塞當(dāng)前線程等待一段時(shí)間直到完成或者異常終止取消任務(wù)。此時(shí),線程從中返回,然后檢查當(dāng)前的狀態(tài)已經(jīng)被改變,隨后退出循環(huán)。 0 引言 前段時(shí)間需要把一個(gè)C++的項(xiàng)目port到Java中,因此時(shí)隔三年后重新熟悉了下Java。由于需要一個(gè)通用的線程池,自然而然就想到了Executors。 用了...

    itvincent 評(píng)論0 收藏0
  • 系列文章目錄

    摘要:為了避免一篇文章的篇幅過(guò)長(zhǎng),于是一些比較大的主題就都分成幾篇來(lái)講了,這篇文章是筆者所有文章的目錄,將會(huì)持續(xù)更新,以給大家一個(gè)查看系列文章的入口。 前言 大家好,筆者是今年才開始寫博客的,寫作的初衷主要是想記錄和分享自己的學(xué)習(xí)經(jīng)歷。因?yàn)閷懽鞯臅r(shí)候發(fā)現(xiàn),為了弄懂一個(gè)知識(shí),不得不先去了解另外一些知識(shí),這樣以來(lái),為了說(shuō)明一個(gè)問(wèn)題,就要把一系列知識(shí)都了解一遍,寫出來(lái)的文章就特別長(zhǎng)。 為了避免一篇...

    lijy91 評(píng)論0 收藏0
  • 系列文章目錄

    摘要:為了避免一篇文章的篇幅過(guò)長(zhǎng),于是一些比較大的主題就都分成幾篇來(lái)講了,這篇文章是筆者所有文章的目錄,將會(huì)持續(xù)更新,以給大家一個(gè)查看系列文章的入口。 前言 大家好,筆者是今年才開始寫博客的,寫作的初衷主要是想記錄和分享自己的學(xué)習(xí)經(jīng)歷。因?yàn)閷懽鞯臅r(shí)候發(fā)現(xiàn),為了弄懂一個(gè)知識(shí),不得不先去了解另外一些知識(shí),這樣以來(lái),為了說(shuō)明一個(gè)問(wèn)題,就要把一系列知識(shí)都了解一遍,寫出來(lái)的文章就特別長(zhǎng)。 為了避免一篇...

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

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

0條評(píng)論

閱讀需要支付1元查看
<