Java基礎之線程Thread

在程序開發中, 必定遇到併發編程的場景, 雖然咱們大部分時間並不直接使用Thread, 可是Thread是多線程的基礎, 面試中也會老是被問到與線程有關的問題; 那麼線程都有哪些知識呢? 最近在研究線程的源碼的時候也總結了關於線程一些基本知識;

線程是什麼

線程是輕量級的進程, 是操做系統調度任務到CPU的最小單元;java

多線程編程的優勢

一、多線程編程可以最大程度的利用多核設備上面的CPU資源, 保證任務處理的足夠快, 及時響應客戶端的額請求面試

二、線程的建立的代價比建立進程的代價小不少, 同時多線程的上下文切換也更快; 《操做系統概念 第六版》 在Solaris 2上面, 建立進程比建立線程慢30倍, 而進程的上下文切換比線程的上下文切換慢5倍;編程

Java中線程的狀態有哪些

查看java.lang.Thread的源碼有以下代碼:多線程

public enum State {
    /**
     * Thread state for a thread which has not yet started.
     */
    NEW,

    /**
     * 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,

    /**
     * Thread state for a thread blocked waiting for a monitor lock.
     * A thread in the blocked state is waiting for a monitor lock
     * to enter a synchronized block/method or
     * reenter a synchronized block/method after calling
     * {@link Object#wait() Object.wait}.
     */
    BLOCKED,

    /**
     * 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,

    /**
     * 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,

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

一、NEW: 線程尚未啓動的時候, 狀態就是NEW 即 新建狀態併發

二、RUNNABLE: 當一個線程處於運行中或者等待CPU調度的時候, 狀態就是 RUNNABLE狀態; 有些地方也稱爲 就緒狀態函數

三、BLOCKED: 當一個線程在等待別的線程釋放鎖資源的時候, 狀態就是BLOCKED, 或者在該線程獲取到鎖以後, 在同步代碼塊裏面調用了Wait方法, 這時候釋放鎖, 在獲取到其餘線程的notify或者notifyAll通知以後, 從新進入 同步代碼塊這段時間 該線程也是BLOCKED狀態的;spa

四、WAITING: 當正在運行的線程調用了Object.wait()方法 或者 Thread.join()方法 或者 LockSupport.park()方法以後, 會進入到WAITING狀態操作系統

五、TIMED_WAITING: 當正在運行的線程調用Object.wait(n) 或者 Thread.join(n) 或者 LockSupport.parkUntil(blocker, n) 會進入到 TIMED_WAITING 狀態線程

六、TERMINATED: 當線程結束後, 會進入到 TERMINATED 狀態.翻譯

狀態轉換以下, 該圖中比Java的狀態多了一個RUNNING狀態, 來區別 線程的就緒狀態 與 運行狀態 更加方便讀者理解;

圖片描述

線程狀態轉換

線程狀態轉換之NEW

下面來看一下線程的狀態轉換用Java怎麼實現:

如上面所述: 剛剛建立的線程處於NEW狀態, 那麼咱們能夠經過以下代碼打印其狀態:

Thread thread = new Thread(new Runnable() {
       public void run() {
       }
    });
    System.out.println(thread.getState());

線程狀態轉換之RUNNABLE

那麼線程如何進入到RUNNABLE狀態呢? 調用Threadstart方法便可; 咱們在Runnable的實現裏面增長對於當前線程狀態的打印便可:

public static void main(String[] args) {
       Thread thread = new Thread(new Runnable() {
           public void run() {
                System.out.println("線程進入:" + Thread.currentThread().getState());
           }
       });

       System.out.println(thread.getState());
       thread.start();
    }

線程狀態轉換之TIMED_WAITING

那麼線程怎麼進入到TIMED_WAITING狀態呢? 經過調用 sleep(n) join(n) 或者 wait(n)均可以進入到TIMED_WAITING狀態:

調用Thread.sleep()

public static void main(String[] args) {
    Thread thread = new Thread(new Runnable() {
        public void run() {
            System.out.println("線程進入:" + Thread.currentThread().getState());
            try {
                Thread.sleep(1000 * 60);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });

    System.out.println(thread.getState());
    thread.start();
}

clipboard.png

調用obj.wait(time)

public static void main(String[] args) {
    Thread thread = new Thread(new Runnable() {
        public void run() {
            synchronized (Client.class) {
                System.out.println("線程進入:" + Thread.currentThread().getState());
                try {
                    Client.class.wait(60 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });

    System.out.println(thread.getState());
    thread.start();
}

clipboard.png

上圖中表示: 在Client.class上面等待; 等待其餘對象調用Client.class.notify()方法或者等待時間到期.

調用thread.join(time)

public static void main(String[] args) {
    final Thread thread = new Thread(new Runnable() {
        public void run() {
            synchronized (Client.class) {
                System.out.println("線程進入:" + Thread.currentThread().getState());
                try {
                    Client.class.wait(60 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Client.class對象上等待超時");
            }
        }
    });

    System.out.println(thread.getState());
    thread.start();

    Thread thread2 = new Thread(new Runnable() {
        public void run() {
            synchronized (Client.class) {
                try {
                    thread.join(50 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread1結束");
            }
        }
    });

    thread2.start();
}

clipboard.png

表示 第二個線程在等待第一個線程執行完成或者超時;

線程狀態轉換之WAITING

若是想要一個線程進入到WAITING狀態, 那麼只須要跟上面步驟同樣, Thread.sleep()除外, 可是調用的時候不要傳超時時間便可;

public static void main(String[] args) {
    final Thread thread = new Thread(new Runnable() {
        public void run() {
            synchronized (Client.class) {
                System.out.println("線程進入:" + Thread.currentThread().getState());
                try {
                    Client.class.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("被其餘線程調用Client.class.notify()喚醒");
            }
        }
    });

    System.out.println(thread.getState());
    thread.start();

    Thread thread2 = new Thread(new Runnable() {
        public void run() {
            synchronized (Client.class) {
                try {
                    thread.join(50 * 1000);
                    Client.class.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread1結束");
            }
        }
    });

    thread2.start();
}

clipboard.png

只要是沒有時間的等待都會處於WAITING狀態, 好比把上面代碼修改一下, 換成join()也可讓線程處於 WAITING狀態:

public static void main(String[] args) {
    final Thread thread = new Thread(new Runnable() {
        public void run() {
            synchronized (Client.class) {
                System.out.println("線程進入:" + Thread.currentThread().getState());
                try {
                    Client.class.wait(50 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("被其餘線程調用Client.class.notify()喚醒");
            }
        }
    });

    System.out.println(thread.getState());
    thread.start();

    Thread thread2 = new Thread(new Runnable() {
        public void run() {
            synchronized (Client.class) {
                try {
                    System.out.println("即將進入等待線程1完成的狀態");
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread1結束");
            }
        }
    });

    thread2.start();
}

如上代碼表示線程2會在線程1執行結束以後再結束, 因此線程2就會進入到WATIING狀態

clipboard.png

線程狀態轉換之BLOCKED

上面已經看到, 經過調用線程的函數就能夠控制線程的狀態, 那麼如何進入到BLOCKED狀態呢?進入到BLOCKED狀態, 按照上面的轉換圖 能夠翻譯爲 多個線程出現竟態的時候, 其餘線程會進入BLOCKED狀態, 只有一個線程會在RUNNABLE狀態,好比以下代碼:

public static void main(String[] args) {
    final Thread thread = new Thread(new Runnable() {
        public void run() {
            synchronized (Client.class) {
                System.out.println("線程進入:" + Thread.currentThread().getState());
                try {
                    Thread.sleep(1000 * 50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });

    System.out.println(thread.getState());
    thread.start();

    Thread thread2 = new Thread(new Runnable() {
        public void run() {
            synchronized (Client.class) {
                try {
                    System.out.println("即將進入等待線程1完成的狀態");
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread1結束");
            }
        }
    });

    thread2.start();
}

clipboard.png

固然, 對於A線程調用了Object.class.wait()方法釋放鎖以後, 最後被其餘線程調用Object.class.notify() A線程再次進入RUNNABLE以前的狀態就是 BLOCKED;

相關文章
相關標籤/搜索