線程Thread基礎知識

一、線程的定義

Java中的線程,簡單來說,就是一段順序執行的代碼,是CPU執行的最小單位。新建並啓動一個線程,本質都是新建一個Thread或Thread子類的對象,然後調用其start方法,最終執行的代碼塊位於run方法內(start方法被調用後,JVM會在某一刻自動執行run方法),start和run方法如下:

/**
 * Causes this thread to begin execution; the Java Virtual Machine
 * calls the <code>run</code> method of this thread.
 * <p>
 * The result is that two threads are running concurrently: the
 * current thread (which returns from the call to the
 * <code>start</code> method) and the other thread (which executes its
 * <code>run</code> method).
 * <p>
 * It is never legal to start a thread more than once.
 * In particular, a thread may not be restarted once it has completed
 * execution.
 *
 * @exception  IllegalThreadStateException  if the thread was already
 *               started.
 * @see        #run()
 * @see        #stop()
 */
public synchronized void start() {
/**
 * If this thread was constructed using a separate
 * <code>Runnable</code> run object, then that
 * <code>Runnable</code> object's <code>run</code> method is called;
 * otherwise, this method does nothing and returns.
 * <p>
 * Subclasses of <code>Thread</code> should override this method.
 *
 * @see     #start()
 * @see     #stop()
 * @see     #Thread(ThreadGroup, Runnable, String)
 */
@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

run方法中,target是Runnable接口的實例。判斷如果target不爲空,那麼就執行其run方法;否則就什麼都不執行。鑑於這種判斷邏輯,新建一個新的有具體執行代碼的執行線程有如下兩種方式:

1、繼承Thread類

  • 聲明一個類繼承Thread類,重寫run方法();
  • 調用該類無參構造方法,新建該類實例;
  • 調用其start方法

2、實現Runnable接口

(優先使用該種方式,原因:多個線程可以同時使用,達到資源共享;java只支持單繼承,但可以實現多接口)

  • 聲明一個類RunnableImpl實現Runnable接口,重寫run方法;
  • 調用Thread類有參構造方法,將RunnableImpl實例作爲入參創建Thread實例;
  • 調用其start方法

二、Thread的常用方法

1、join(加入)

在線程A中調用線程B的join方法後,直到B執行結束後,位於join方法後的A的代碼纔會被執行

/**
 * Waits for this thread to die.
 *
 * <p> An invocation of this method behaves in exactly the same
 * way as the invocation
 *
 * <blockquote>
 * {@linkplain #join(long) join}{@code (0)}
 * </blockquote>
 *
 * @throws  InterruptedException
 *          if any thread has interrupted the current thread. The
 *          <i>interrupted status</i> of the current thread is
 *          cleared when this exception is thrown.
 */
public final void join() throws InterruptedException {
    join(0);
}

首先看不使用join方法的情況下,在main線程中啓動一個線程t,此時兩個線程併發執行,代碼如下:

public class TestJoin {

    public static void main(String[] args) {
        MyThread t = new MyThread("t");
        t.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("I am main thread");
        }
    }

}

class MyThread extends Thread {

    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("I am " + getName());
        }
    }
}

部分輸出結果如下,可以看出main線程和t線程在交替執行

I am main thread
I am t
I am main thread
I am main thread
I am main thread
I am main thread
I am main thread
I am main thread
I am t
I am t

此時如果在啓動t線程後,接着調用t的join方法後,main線程只有等到t線程run方法執行結束後,纔會執行後面的代碼

public class TestJoin {

    public static void main(String[] args) {
        MyThread t = new MyThread("t");
        t.start();
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 100; i++) {
            System.out.println("I am main thread");
        }
    }

}

class MyThread extends Thread {

    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("I am " + getName());
        }
    }
}

部分輸出結果如下,線程t先執行完,然後線程main纔會執行

I am t
I am t
I am t
I am t
I am t
I am t
I am main thread
I am main thread
I am main thread
I am main thread
I am main thread
I am main thread
I am main thread

注意:同時調用t1和t2的join方法後,t1和t2的執行情況是隨機的,互不干擾。且只有等到t1和t2都執行完,main方法後面的代碼纔會執行

public static void main(String[] args) {
    MyThread t1 = new MyThread("t1");
    MyThread t2 = new MyThread("t2");
    t1.start();
    t2.start();
    try {
        t1.join();
        t2.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    for (int i = 0; i < 100; i++) {
        System.out.println("I am main thread");
    }
}

2、yield(讓步)

在當前線程中調用yield方法,表示告訴調度程序,當前線程願意讓出當前分到的時間片,這樣其他線程就可以獲取到更多的執行時間片

/**
 * A hint to the scheduler that the current thread is willing to yield
 * its current use of a processor. The scheduler is free to ignore this
 * hint.
 *
 * <p> Yield is a heuristic attempt to improve relative progression
 * between threads that would otherwise over-utilise a CPU. Its use
 * should be combined with detailed profiling and benchmarking to
 * ensure that it actually has the desired effect.
 *
 * <p> It is rarely appropriate to use this method. It may be useful
 * for debugging or testing purposes, where it may help to reproduce
 * bugs due to race conditions. It may also be useful when designing
 * concurrency control constructs such as the ones in the
 * {@link java.util.concurrent.locks} package.
 */
public static native void yield();

首先正常啓動兩個線程t1、t2後,輸出結果一般是t1執行一段時間,t2執行一段時間

public class TestYield {

    public static void main(String[] args) {
        MyThread2 t1 = new MyThread2("t1");
        MyThread2 t2 = new MyThread2("t2");
        t1.start();
        t2.start();
    }

}

class MyThread2 extends Thread {

    public MyThread2(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("I am " + getName() + " , i = " + i);
        }
    }
}

部分輸出結果,可以看出結果是很隨機的

I am t1 , i = 0
I am t2 , i = 0
I am t1 , i = 1
I am t1 , i = 2
I am t1 , i = 3
I am t1 , i = 4
I am t1 , i = 5
I am t2 , i = 1
I am t1 , i = 6
I am t2 , i = 2
I am t1 , i = 7

如果在run方法中判斷當i % 10 == 0條件成立時就調用當前線程的yield,那麼當某個線程的i滿足該條件時,下一個獲取CPU時間片的一定是另外一個線程

public class TestYield {

    public static void main(String[] args) {
        MyThread2 t1 = new MyThread2("t1");
        MyThread2 t2 = new MyThread2("t2");
        t1.start();
        t2.start();
    }

}

class MyThread2 extends Thread {

    public MyThread2(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("I am " + getName() + " , i = " + i);
            if (i % 10 == 0) {
                Thread.yield();
            }
        }
    }
}

3、setPriority(設置優先級)

優先級越高,線程獲取到的CPU執行時間片越多。在Thread類中有如下三個關於優先級的靜態變量,最小值爲1,最大值爲10,默認值爲5

/**
 * The minimum priority that a thread can have.
 */
public final static int MIN_PRIORITY = 1;
**
 * The default priority that is assigned to a thread.
 */
public final static int NORM_PRIORITY = 5;
/**
 * The maximum priority that a thread can have.
 */
public final static int MAX_PRIORITY = 10;

如下代碼,將t2的優先級在默認值上加3,可以使t2獲取到更多的執行時間片

public class TestPriority {

    public static void main(String[] args) {
        MyThread3 t1 = new MyThread3("t1");
        MyThread3 t2 = new MyThread3("t2");
        t2.setPriority(Thread.NORM_PRIORITY + 3);
        t1.start();
        t2.start();
    }

}

class MyThread3 extends Thread {

    public MyThread3(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("I am " + getName() + " , i = " + i);
        }
    }
}

4、

三、線程的幾種狀態

1、new(新建)

未調用start方法的線程狀態

/**
 * Thread state for a thread which has not yet started.
 */
NEW
static void state_new() {
    Thread thread = new Thread();
    System.out.println(thread.getState());/輸出結果爲NEW
}

2、RUNNABLE(運行)

正在被JVM執行的線程狀態

/**
 * Thread state for a runnable thread.  A thread in the runnable
 * state is executing in the Java virtual machine but it may
 * be waiting for other resources from the operating system
 * such as processor.
 */
RUNNABLE
/**
 * 當JVM在執行run方法體時(注意:不要調用sleep方法),此時線程狀態爲RUNNABLE
 * 當run方法體執行結束後,變成TERMINATED
 */
static void state_runnable() {
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i < Integer.MAX_VALUE; i++) {
                for (int j = 0; j < Integer.MAX_VALUE; j++) {
                }
            }
        }
    });
    thread.start();
    while (true) {
        System.out.println(thread.getState());
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

輸出結果如下

RUNNABLE
TERMINATED
TERMINATED

3、TERMINATED(終止)

run方法體執行結束的線程狀態,實驗代碼如上

/**
 * Thread state for a terminated thread.
 * The thread has completed execution.
 */
TERMINATED

4、WAITING(等待)

當一個線程等待另外一個線程執行結束後才能繼續執行的線程狀態,可以通過調用無參的join()方法實現

/**
 * Thread state for a waiting thread.
 * A thread is in the waiting state due to calling one of the
 * following methods:
 * <ul>
 *   <li>{@link Object#wait() Object.wait} with no timeout</li>
 *   <li>{@link #join() Thread.join} with no timeout</li>
 *   <li>{@link LockSupport#park() LockSupport.park}</li>
 * </ul>
 *
 * <p>A thread in the waiting state is waiting for another thread to
 * perform a particular action.
 *
 * For example, a thread that has called <tt>Object.wait()</tt>
 * on an object is waiting for another thread to call
 * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
 * that object. A thread that has called <tt>Thread.join()</tt>
 * is waiting for a specified thread to terminate.
 */
WAITING

如下代碼,在main線程中調用thread的join方法後,main線程就一直處於WAITING狀態

static void state_waiting() {
    //獲取main線程
    Thread mainThread = Thread.currentThread();
    //新建線程
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                System.out.println("main線程狀態:" + mainThread.getState());;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }
        }
    });
    thread.start();
    try {
        //join方法表示直到thread線程執行結束後,main線程纔會繼續執行
        thread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

5、TIMED_WAITING(定時等待)

當一個線程等待另外一個線程執行結束後才能繼續執行的線程狀態,可以通過調用有參的join(long)方法實現

/**
 * Thread state for a waiting thread with a specified waiting time.
 * A thread is in the timed waiting state due to calling one of
 * the following methods with a specified positive waiting time:
 * <ul>
 *   <li>{@link #sleep Thread.sleep}</li>
 *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
 *   <li>{@link #join(long) Thread.join} with timeout</li>
 *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
 *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
 * </ul>
 */
TIMED_WAITING

代碼如下,注意此時用的是join的有參方法

static void state_timed_waiting() {
    //獲取main線程
    Thread mainThread = Thread.currentThread();
    //新建線程
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                System.out.println("main線程狀態:" + mainThread.getState());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }
        }
    });
    thread.start();
    try {
        //join(5000)方法表示等待thread線程執行5000ms後,main線程就會繼續執行
        thread.join(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("main線程繼續執行");
}

輸出結果

main線程狀態:TIMED_WAITING
main線程狀態:TIMED_WAITING
main線程狀態:TIMED_WAITING
main線程狀態:TIMED_WAITING
main線程狀態:TIMED_WAITING
main線程繼續執行
main線程狀態:TERMINATED
main線程狀態:TERMINATED
main線程狀態:TERMINATED

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章