java 面試知識點筆記(九)多線程與併發 下篇

問:線程有哪些狀態?java

  1. 新建(new):建立後還沒有啓動的線程的狀態(新建立的線程但尚未調用start方法)
  2. 運行(Runnable):包含Running和Ready(Running線程位於可運行線程中,等待調度選中獲取CPU使用權,處於Ready狀態的線程位於線程池中,等待調度選中,選中獲取CPU時間後變爲Running狀態)
  3. 無限期等待(Waiting):不會被分配CPU執行時間,須要顯式喚醒(notify、notifyAll),如下3個方法會讓線程陷入無限期等待狀態:
    1. 沒有設置Timeout參數的Object.wait()方法
    2. 沒有設置Timeout參數的Thread.join()方法
    3. LockSupport.park()方法
  4. 限期等待(Timed Waiting):在必定時間後會由系統自動喚醒(也不會分配CPU執行時間)如下方法會讓線程進入限期等待:
    1. Thread.sleep()方法
    2. 設置了Timeout參數的Object.wait()方法
    3. 設置了Timeout參數的Thread.join()方法
    4. ​LockSupport.parkNanos()方法
    5. LockSupport.parkUntil()方法
  5. 阻塞(Blocked):等待獲取排他鎖(如synchronized同步代碼塊或方法會出現此狀態)
  6. 結束(Terminated):已終止線程的狀態,線程已經結束執行(結束狀態的線程再調用start方法會拋出java.lang.IllegalThreadStateException異常)

問:sleep和wait的區別?安全

  • sleep是Thread類的方法,wait是Object類的方法
  • sleep方法是能夠在任何方法使用
  • wait方法只能在synchronized方法或者synchronized塊中使用(由於只有獲取鎖了才能釋放鎖)

最主要的本質區別:ide

  1. Thread.sleep只會讓出CPU,不會致使鎖行爲的改變
  2. Object.wait不只讓出CPU,還會釋放已經佔有的同步資源鎖

Thread.java中的函數

Object.java中的oop

package interview.thread;

/**
 * wait和sleep的區別
 * @Author: cctv
 * @Date: 2019/5/17 11:49
 */
public class WaitSleepDemo {
    public static void main(String[] args) {
        final Object lock = new Object();
        new Thread(() -> {
            System.out.println("thread A is waiting to get lock");
            synchronized (lock) {
                try {
                    System.out.println("thread A get lock");
                    // 先等B運行起來再到下一步
                    Thread.sleep(20);
                    System.out.println("thread A do wait method");
                    // wait讓出CPU和鎖 B會搶到鎖執行B後再執行A
//                    lock.wait(1000);

                    // sleep不會讓出鎖 A執行完了以後再執行B
                    Thread.sleep(1000);
                    System.out.println("thread A is done");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        // 先啓動A拿到鎖,再讓B也運行
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            System.out.println("thread B is waiting to get lock");
            synchronized (lock) {
                try {
                    System.out.println("thread B get lock");
                    System.out.println("thread B do wait method");
                    Thread.sleep(10);
                    System.out.println("thread B is done");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();


    }
}

sleep結果:測試

wait結果:線程

 

問:notify和notifyAll的區別?code

首先了解2個概念:對象

  1. 鎖池EntryList(一個鎖資源被佔用以後其餘其餘線程想要獲取鎖就進入了阻塞狀態,在一個地方等待鎖的釋放,這個地方就是鎖池)
  2. 等待池WaitSet(線程調用某對象的wait方法以後舊進入等待狀態,進入等待池中,進入等待吃的線程不會去競爭該對象的鎖)

notifyAll會讓全部處於等待池的線程所有進入鎖池去競爭獲取鎖的機會blog

notify是隨機選擇一個處於等待池的線程進入鎖池去競爭獲取鎖的機會

問:yiled的含義?

當調用Thread.yield()函數時,會給線程調度器一個當前線程願意讓出CPU使用的暗示,可是線程調度器可能會忽略這個暗示。

yield並不會讓出當前佔用的鎖

 

問:如何中斷線程?

  • 已被拋棄的方法:
    • 經過調用stop()方法中止線程(這種方法太過暴力,並且是不安全的。忽然調用stop中止了線程,致使線程的一些清理工做沒法完成,並且會釋放鎖,可能致使數據不一樣步的問題)
    • 經過調用suspend()和resume()方法(緣由和stop相似)
  • 目前使用的方法:
    • 調用interrupt(),通知線程應該中斷了
    1. 若是線程處於被阻塞狀態,那麼線程將馬上退出被阻塞狀態,並拋出一個InterruptedException異常
    2. 若是線程處於正常活動狀態,那麼會將該線程的中斷標誌設置爲true。被設置中斷標誌的線程將繼續正常運行,不受影響
    • 須要被調用的線程配合中斷:
    1. 在阻塞阻塞線程裏,處理InterruptedException異常,並在catch裏作好相關清理工做
    2. 在正常運行任務時,常常檢查本線程的中斷標誌位(Thread.currentThread().isInterrupted()方法判斷),若是被設置了中斷標誌就自行中止線程

測試:

package interview.thread;

/**
 * 中斷線程demo
 *
 * @Author: cctv
 * @Date: 2019/5/20 10:26
 */
public class InterruptDemo {
    public static void main(String[] args) throws InterruptedException {
        Runnable interruptTask = new Runnable() {
            @Override
            public void run() {
                int i = 0;
                Thread t = Thread.currentThread();
// 加上註釋看阻塞狀態的處理 去掉註釋看工做狀態的處理
//                try {
                    while (!t.isInterrupted()) {
//                        Thread.sleep(100);
                        i++;
                        System.out.println(t.getName() + "(" + t.getState() + ") loop " + i);
                    }
                    System.out.println(t.getName() + "(" + t.getState() + ") Thread isInterrupted is true. loop is" + i);
//                } catch (InterruptedException e) {
//                    System.out.println(t.getName() + "(" + t.getState() + ") catch InterruptedException. loop is " + i);
//                }
            }
        };
        Thread t1 = new Thread(interruptTask, "t1");
        System.out.println(t1.getName() + "(" + t1.getState() + ") is new");

        t1.start();
        System.out.println(t1.getName() + "(" + t1.getState() + ") is started");

        Thread.sleep(300);
        t1.interrupt();
        System.out.println(t1.getName() + "(" + t1.getState() + ") is interrupted");

        Thread.sleep(300);
        System.out.println(t1.getName() + "(" + t1.getState() + ") is terminated");
    }
}

相關文章
相關標籤/搜索