天天看點

【學習筆記之JavaSE】-6.多線程0.基本概念1.建立2.線程的同步3.線程通信

文章目錄

  • 0.基本概念
  • 1.建立
  • 2.線程的同步
  • 3.線程通信

0.基本概念

線程與程序

1.程序(process):是程式(指令集合)的一次執行過成,動态的(的産生、存在和消亡)即生命周期。程序作為資源配置設定的機關,一個程序中的多個線程共享相同的記憶體單元/記憶體位址空間。

2.線程(thread),程序可進一步細化為線程,是一個程式内部的一條執行路徑。線程作為排程和執行的機關,每個線程擁有獨立的運作棧和程式計數器(pc)。

【學習筆記之JavaSE】-6.多線程0.基本概念1.建立2.線程的同步3.線程通信

yield():釋放目前cpu的執行權

sleep(long millitime):讓目前線程“睡眠”指定millitime毫秒。在指定的millitime毫秒時間内,目前線程是阻塞狀态。

join():線上程a中調用線程b的join()此時線程a就進入阻塞狀态,直到線程b完全執行完以後,線程a才結束阻塞狀态。

并行與并發

1.并行:多個CPU同時執行多個任務。比如:多個人同時做不同的事。

2.并發:一個CPU(采用時間片)同時執行多個任務。比如:秒殺、多個人做同一件事。但肉眼錯覺,主頻太快看不出交替輪流。

1.建立

方式一:繼承于Thread類

  1. 建立一個繼承于Thread類的子類

    class MyThread extends Thread {

  2. 重寫Thread類的run() --> 将此線程執行的操作聲明在run()中 PS:由于該類對象調用該線程的重寫方法故這裡Thread.currentThread().getName()等同于this.getName()

    }

  3. 建立Thread類的子類的對象

    MyThread t1 = new MyThread();

  4. 通過此對象調用start():①啟動目前線程 ② 調用目前線程的run()

    t1.start();

    PS:一個對象智能執行一次start,否則會報IllegalThreadStateException

方式二:實作Runnable接口

  1. 建立一個實作了Runnable接口的類

    class MThread implements Runnable{

  2. 實作類去實作Runnable中的抽象方法:run()

    }

  3. 建立實作類的對象:MThread mThread = new MThread();
  4. 将此對象作為參數傳遞到Thread類的構造器中,建立Thread類的對象:

    Thread t1 = new Thread(mThread);

    t1.setName(“線程一”); //執行個體Thread可以直接帶參"線程一"

  5. 通過Thread類的對象調用start():① 啟動線程 ②調用目前線程的run()–>調用了Runnable類型的target的run()

比較方式一與方式二:

  • 聯系:1. public class Thread implements Runnable;2.兩種方式都需要重寫run(),将線程要執行的邏輯聲明在run()中。
  • Runnable接口的方式 1. 實作的方式沒有類的單繼承性的局限性; 2. 實作的方式更适合來處理多個線程有共享資料的情況。

方式三:實作Callable接口

//1.建立一個實作Callable的實作類
class NumThread implements Callable{
    //2.實作call方法,将此線程需要執行的操作聲明在call()中
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if(i % 2 == 0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}

//3.建立Callable接口實作類的對象:
NumThread numThread = new NumThread();
//4.将此Callable接口實作類的對象作為傳遞到FutureTask構造器中,建立FutureTask的對象:
FutureTask futureTask = new FutureTask(numThread);
 //5.将FutureTask的對象作為參數傳遞到Thread類的構造器中,建立Thread對象,并調用start():
 new Thread(futureTask).start();
//6.擷取Callable中call方法的傳回值
//get()傳回值即為FutureTask構造器參數Callable實作類重寫的call()的傳回值:
Object sum = futureTask.get();
           

比實作Runnable接口建立多線程方式強大:

1.call()可以有傳回值的。

2.call()可以抛出異常,被外面的操作捕獲,擷取異常的資訊

3.Callable是支援泛型的

方式四:使用線程池

  1. 提供指定線程數量的線程池

    ExecutorService service = Executors.newFixedThreadPool(10);

    ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;

    //設定線程池的屬性

    // service1.setCorePoolSize(15);

    //service1.setKeepAliveTime();

  2. 執行指定的線程的操作。需要提供實作Runnable接口或Callable接口實作類的對象

    service.execute(Runnalble的實作類對象);//适合适用于Runnable

    // service.submit(Callable callable);//适合使用于Callable

  3. 關閉連接配接池

    service.shutdown();

2.線程的同步

方式一:同步代碼塊

synchronized(同步螢幕){
       //需要被同步的代碼
 }
           

PS:

1.操作共享資料的代碼,即為需要被同步的代碼。

2.共享資料:多個線程共同操作的變量。–>不能包含代碼多了,也不能包含代碼少了。

3.同步螢幕,俗稱:鎖。任何一個類的對象,都可以充當鎖。要求:多個線程必須要共用同一把鎖。

4.在實作Runnable接口建立多線程的方式中,我們可以考慮使用this充當同步螢幕。在繼承Thread類建立多線程的方式中,慎用this充當同步螢幕,考慮使用目前類(類名.class)充當同步螢幕

方式二:同步方法。

如果操作共享資料的代碼完整的聲明在一個方法中,我們不妨将此方法聲明同步的。

private static synchronized void 方法名(){

}
           

PS同步方法仍然涉及到同步螢幕,隻是不需要我們顯式的聲明:

非靜态的同步方法,同步螢幕是:this

靜态的同步方法,同步螢幕是:目前類本身

同步機制解決了線程的安全問題。但操作同步代碼時,隻能有一個線程參與,其他線程等待。相當于是一個單線程的過程,效率低。

方式三:Lock鎖

//1.執行個體化ReentrantLock
    private ReentrantLock lock = new ReentrantLock(); 
    try{
        //2.調用鎖定方法lock()
        lock.lock();
        //操作共享資料的代碼
        ...
    }finally{
	//3.調用解鎖方法:unlock()
        lock.unlock();
    }
           

synchronized 與 Lock的異同?

相同:二者都可以解決線程安全問題

不同:1.synchronized機制在執行完相應的同步代碼以後,自動的釋放同步螢幕;2. Lock需要手動的啟動同步(lock()),同時結束同步也需要手動的實作(unlock())

死鎖:同一把鎖(同步螢幕)下的允許線程隻有一個。不同的線程分别占用對方需要的同步資源不放棄,都在等待對方放棄自己需要的同步資源,就形成了線程的死鎖。

3.線程通信

涉及的方法:

wait():一旦執行此方法,目前線程就進入阻塞狀态,并釋放同步螢幕。

notify():一旦執行此方法,就會喚醒被wait的一個線程。如果有多個線程被wait,就喚醒優先級高的那個。

notifyAll():一旦執行此方法,就會喚醒所有被wait的線程。

PS:

1.wait(),notify(),notifyAll()三個方法必須使用在同步代碼塊或同步方法中。

2.wait(),notify(),notifyAll()三個方法的調用者必須是同步代碼塊或同步方法中的同步螢幕。否則,會出現IllegalMonitorStateException異常

3.wait(),notify(),notifyAll()三個方法是定義在java.lang.Object類中。

面試題:sleep() 和 wait()的異同?

  • 相同點:一旦執行方法,都可以使得目前的線程進入阻塞狀态。
  • 不同點:1.兩個方法聲明的位置不同:Thread類中聲明sleep() , Object類中聲明wait(); 2.調用的要求不同:sleep()可以在任何需要的場景下調用。wait()必須使用在同步代碼塊或同步方法中;3.關于是否釋放同步螢幕:如果兩個方法都使用在同步代碼塊或同步方法中,sleep()不會釋放鎖

繼續閱讀