Java多線程(課堂筆記)

Process與Thread

◆線程就是獨立的執行路徑;
◆在程序運行時,即使沒有自己創建線程,後臺也會有多個線程,如主線程,gc線程
◆main()稱之爲主線程,爲系統的入口,用於執行整個程序; .
◆在一個進程中,如果開闢了多個線程,線程的運行由調度器安排調度,調度器是與
操作系統緊密相關的,先後順序是不能認爲的干預的。
◆對同一份資源操作時,會存在資源搶奪的問題,需要加入併發控制;
◆線程會帶來額外的開銷,如cpu調度時間,併發控制開銷。
◆每個線程在自己的工作內存交互,內存控制不當會造成數據不一致

在這裏插入圖片描述

Java多線程

  • 程序、進程、線程的概念

  • Java中多線程的創建和使用

    • 繼承Thread類與實現Runnable接口
    • Thread類的主要方法
    • 線程的調度與設置優先級周
  • 線程的生命週期

  • 線程的同步

  • 線程的通信

一、基本概念

程序-進程-線程

  • 程序(program)是爲完成特定任務、用某種語言編寫的一組指令的集合。即指一段靜態的代碼,靜態對象。
  • 進程(process)是程序的一次執行過程,或是正在運行的一個程序。動態過程:有它自身的產生存在和消亡的過程。
    • 如:運行中的QQ,運行中的MP3播放器
    • 程序是靜態的,進程是動態的
  • 線程(thread),進程可進一步細化爲線程,是一個程序內部的一條執行路徑
    • 若一個程序 可同一時間執行多個線程,就是支持多線程的

二、多線程的創建和啓動

//創建多線程的第一種方式:一.繼承java.lang.Thread類

  • Java語言的JVM允許程序運行多個線程,它通過java.lang.Thread類來實現。
  • Thread類的特性
    • 每個線程都是通過某個特定Thread對象的run()方法來完成操作的,經常把run()方法的主體稱爲線程體
    • 通過Thread對象的start()方法來調用這個線程
package Thread01;

//創建一個子線程,完成1-100自然數的輸出。同樣的,主線程執行同樣的操作
//創建多線程的第一種方式:一.繼承java.lang.Thread類

//1.創建一個繼承於Thread的子類
class SubThread extends Thread{
    //2.重寫Thread類的run()方法,方法內實現此子線程要完成的功能
    @Override
    public void run() {
        for (int i = 1; i <=100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

public class TestThread {
    public static void main(String[] args) {
        //3.創建一個子類對象
        SubThread subThread1 = new SubThread();
        SubThread subThread2 = new SubThread();
        //4.調用線程的start()方法,啓動此線程:調用相應的run()方法
        subThread1.start();
        subThread2.start();

//        subThread.start();
//      一個線程只能執行一次start()

//        subThread.run();
//      不能通過Thread實現類對象run()去啓動一個線程
        for (int i = 1; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

在這裏插入圖片描述

三、線程的調度

  • 調度策略

    • 時間片在這裏插入圖片描述
    • 搶佔式:高優先級的線程搶佔CPU
  • Java的調度方法

    • 同優先級線程組成先進先出隊列(先來先服務),使用時間片策略
    • 對高優先級,使用優先調度的搶佔式策略
  • 線程的優先級控制

    • MAX_PRIORITY(10);
    • MIN_PRIORITY(1);
    • NORM_PRIORITY(5);
    • 涉及的方法
      • getPriority():返回線程優先值
      • setPriority(int newPriority):改變線程的優先級
      • 線程創建時繼承父線程的優先級
package Thread02;
/*
* Thread常用方法
* 1.start(),啓動線程並執行相應的run()方法
* 2.run():子線程要執行的代碼放入run()方法中
* 3.currentThread(),靜態的,調取當前的線程
* 4.getName():獲取此線程的名字
* 5.setName():設置此線程的名字
* 6.yield():調用此方法的線程釋放當前CPU的執行權
* 7.join():在A線程中調用B線程的join方法.表示,
* 當執行到此方法,A線程停止執行,直至B線程執行完畢,
* A線程再接着join()之後的代碼執行
* 8.isAlive():判斷當前線程是否還存活
* 9.sleep(long l):顯式的讓當前線程睡眠l毫秒
* 10.線程通信:wait()   notify()  notifyAll()
*
* 設置線程的優先級
* - getPriority():返回線程優先值
* - setPriority(int newPriority):改變線程的優先級
* //優先級增加搶佔CPU的概率
* */

class SubThread extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <=100; i++) {
//            try {
//                Thread.currentThread().sleep(100);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+":"+i);
        }
    }
}
public class TestThread {
    public static void main(String[] args) {
        SubThread subThread = new SubThread();
        subThread.setName("子線程1");
//        subThread.setPriority(10);
        subThread.setPriority(Thread.MAX_PRIORITY);
        subThread.start();
        Thread.currentThread().setName("====主線程");
        for (int i = 1; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+":"+i);
//            if (i%10==0){
//                Thread.currentThread().yield();
//            }
//            if (i==20){
//                try {
//                    subThread.join();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
        }
        System.out.println(subThread.isAlive());
    }
}

四、實現方式二

package Thread02;
/*
* //創建多線程的方式二,通過實現的方式
*
* 對比一下繼承的方式 VS 實現的方式
* 1.聯繫,public class Thread implements Runnable
* 2.哪個方式好?  實現的方式優於繼承的方式
*   爲什麼 why?
* ①避免了java單繼承的侷限性
* ②如果多線程要操作同一份資源(或數據),更適合使用實現的方式
* */
//1.創建一個實現了Runnable接口的類
class PrintNum1 implements Runnable{
//2.實現接口的抽象方法
    @Override
    public void run() {
        //子線程執行的代碼
        for (int i = 1; i <=100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
public class TestThread1 {
    public static void main(String[] args) {
        //3.創建一個Runnable接口實現類的對象
        PrintNum1 printNum1 = new PrintNum1();
//        printNum1.start();//無此方法
//        printNum1.run();//不是多線程
        //要想啓動一個多線程,必須調用start()
        //4.將此對象作爲形參傳遞給Thread類的構造器中,創建Thread類的對象此對象即爲一個線程
        Thread thread = new Thread(printNum1);
        //5.調用start()方法,啓動線程並執行run()方法
        thread.start();//啓動線程,執行Thread對象生成時構造器形參的對象的run()方法

        //再創建一個線程
        Thread thread1 = new Thread(printNum1);
        thread1.start();
    }
}

五、使用多線程的優點

  1. 提高應用程序的響應。對圖形化界面更有意義,可增強用戶體驗
  2. 提高計算機系統CPU的利用率
  3. 改善程序結構。將即長又複製的進程分爲多個下次,獨立運行,利於理解和修改

生命週期五種狀態:

新建:當一個Thread類或其子類的對象被聲明並創建時,新生的線程對象處於新建狀態

就緒:處於新建狀態的線程被start()後,將進入線程隊列等待CPU時間片

此時它已具備了運行條件

運行:當就緒的線程被調度並獲得處理器資源時。便進入運行狀態,run()方法定義了線程的操作和功能

阻塞:在某種特殊情況下,被人爲掛起或執行輸入輸出操作時,讓出CPU
並臨時中止自己的執行,進入阻塞狀態

死亡:線程完成了它的全部工作或線程被提前強制性地中止

在這裏插入圖片描述

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