1. 程式人生 > 其它 >Java執行緒基礎學習筆記(正在更新)

Java執行緒基礎學習筆記(正在更新)

最近一直在跟著B站韓順平老師的《零基礎快速學Java》視訊教程學習Java基礎知識,教程地址——https://www.bilibili.com/video/BV1fh411y7R8?spm_id_from=333.999.0.0, 目前已經學到了程式程序執行緒基礎部分,在學習過程中做了一些相關的學習筆記和心得,分享在部落格,就當做是基礎強化了,哈哈哈。

執行緒基礎

1.執行緒介紹

1.1程序

程序是指執行中的程式,作業系統為啟動的程式分配記憶體空間;

程序是程式的一次執行過程,或是一個正在執行的程式。是一個動態的過程:有它自己的產生、存在和消亡的過程

1.2執行緒

執行緒由程序建立,是程序的一個實體

一個程序可以擁有多個執行緒

1.3併發與並行

併發:同一時刻,多個任務交替執行。單核CPU可以實現

並行:同一時刻,多個任務同時執行。多核CPU可以實現

2.執行緒使用

2.1繼承Thread建立執行緒

package thread;
@SuppressWarnings({"all"})
/**
 * @Author Blueshadow
 * @Date 2021/7/26 9:24
 * @Version 1.0
 *
 * 程式啟動就開起了一個程序
 * 進入到main方法之後,就開啟了一個主執行緒
 * 通過hello.start()開啟了子執行緒Thread-0
 */
public class thread  {
    public static void main(String[] args) throws InterruptedException {
        Hello hello = new Hello();//建立一個物件,當做執行緒來使用
        hello.start();//啟動子執行緒Thread-0
//        hello.run();//此時run方法是一個普通的方法,沒有真正的啟動一個執行緒,等run方法執行完畢之後,才回去執行之後的程式碼(阻塞)
        //當main執行緒啟動一個子執行緒之後,主執行緒不會阻塞,會繼續執行,子執行緒和主執行緒交替執行
        System.out.println("主執行緒"+Thread.currentThread().getName());//main
        for (int i = 0; i < 60 ; i++) {
            System.out.println("主執行緒 main 執行次數="+i);
            Thread.sleep(1000);//丟擲異常
        }
    }
}
@SuppressWarnings({"all"})
//當一個類繼承了Thread方法,那麼該類可以當做一個執行緒類了
class Hello extends Thread{

    @Override
    public void run() {//重寫run方法(該方法通過實現Runnable介面中的run方法),寫上自己的業務邏輯
        int times = 0;
        while (true){
            System.out.println("Hello world "+(++times) + "子執行緒名稱"+ Thread.currentThread().getName());
            //讓執行緒休眠一秒
            try {//通過try Catch處理異常
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }if (times == 80){
                break;//當times等於80的時候,退出迴圈,此時執行緒也退出
            }
        }
    }
}

2.2多執行緒機制

//上面的程式通過hello.start()方法來實現多執行緒,因為如果直接呼叫執行緒類裡面的run方法的話,實現的就是一個主執行緒即main執行緒,而不是thread-0執行緒了,在底層,通過JVM來實現start方法,去啟東一個子執行緒

2.3實現Runnable介面建立執行緒

package thread;
@SuppressWarnings({"all"})
/**
 * @Author Blueshadow
 * @Date 2021/7/26 9:24
 * @Version 1.0
 *
 * 通過實現介面Runnable來建立執行緒
 */
public class thread  {
    public static void main(String[] args) {
        Hello hello = new Hello();
//        hello.start();//這裡不能呼叫start方法
        Thread thread = new Thread(hello);//建立了一個Thread物件,把已經實現了Runnable介面的Hello物件放入Thread物件中
        thread.start();
    }
}

class Hello implements Runnable{
    @Override
    public void run() {
        int num = 0;
        while (true){
            System.out.println("hello"+(++num)+"     執行緒名稱>>>"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }if (num == 10){
                break;
            }
        }
    }
}

2.4多個子執行緒案例

package thread;
@SuppressWarnings({"all"})
/**
 * @Author Blueshadow
 * @Date 2021/7/26 9:24
 * @Version 1.0
 *
 * 在main執行緒啟動兩個子執行緒
 */
public class thread  {
    public static void main(String[] args) {
        Hello hello = new Hello();
        World world = new World();
        Thread thread1 = new Thread(hello);
        Thread thread2 = new Thread(world);
        thread1.start();
        thread2.start();
    }
}

class Hello implements Runnable{
    @Override
    public void run() {
        int num = 0;
        while (true){
            System.out.println("Hello "+(++num)+"執行緒名:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }if (num == 10){
                break;
            }
        }
    }
}

class World implements Runnable{
    @Override
    public void run() {
        int num = 0;
        while (true){
            System.out.println("world "+(++num)+"執行緒名:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }if (num == 5){
                break;
            }
        }
    }
}

2.5多執行緒售票問題

package thread;
@SuppressWarnings({"all"})
/**
 * @Author Blueshadow
 * @Date 2021/7/26 9:24
 * @Version 1.0
 *
 * 使用多執行緒模擬三個視窗同時售票100張
 */
public class thread  {
    public static void main(String[] args) {
        //建立視窗
        SellTicket01 sellTicket01 = new SellTicket01();
        SellTicket01 sellTicket02 = new SellTicket01();
        SellTicket01 sellTicket03 = new SellTicket01();
        //出現票數超賣問題,可以通過Synchronized來解決該問題(執行緒的同步和互斥)
        sellTicket01.start();
        sellTicket02.start();
        sellTicket03.start();
    }
}

//使用繼承Thread類建立執行緒
class SellTicket01 extends Thread{
    private static int num = 100;//讓多個執行緒共享這個票數
    @Override
    public void run() {
        while (true){
            if (num <= 0){
                System.out.println("售票結束");
                break;
            }
            //售票休眠50毫秒
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("視窗 "+Thread.currentThread().getName()+"售出一張票"
            + "剩餘票數" +(--num)
            );
        }
    }
}

2.6通知執行緒退出

執行緒完成之後自動退出

程式碼條件執行完畢,執行緒自動退出,但是主執行緒退出之後,子線執行緒不一定退出

通知執行緒退出

通過使用變數來控制run方法退出的方式停止執行緒

package thread;
@SuppressWarnings({"all"})
/**
 * @Author Blueshadow
 * @Date 2021/7/31 15:28
 * @Version 1.0
 */
public class thread_exit {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.start();

        Thread.sleep(10000);
        //通過主執行緒控制子執行緒的終止,必須可以修改loop變數
        //修改loop為false之後,退出run方法>>>通知方式
        t.setLoop(false);
    }
}
class T extends Thread{
    //設定一個控制變數
    private boolean loop = true;
    @Override
    public void run() {
        int count = 0;
        while (loop){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Hello world..."+(++count));
        }
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}

3.執行緒方法

3.1執行緒常用方法

setName//設定執行緒名稱,使之與引數name相同

getName//返回該執行緒的名字

start//使該執行緒開始執行;Java虛擬機器底層呼叫該diaman執行緒的start0()方法

run//呼叫執行緒物件run方法

setPriority//更改執行緒的優先順序

getPriority//獲取執行緒額優先順序

sleep//在指定的毫秒數內讓當前正在執行的執行緒休眠(即暫停執行)

interrupt//中斷執行緒
yield//執行緒的禮讓。讓出CPU,讓其他執行緒執行,但禮讓的時間不確定,所以不一定會禮讓成功

join//執行緒的插隊。插隊的執行緒一旦插隊成功,則一定會先執行完插入的執行緒的所有的任務

3.2執行緒中斷

package thread;
@SuppressWarnings({"all"})
/**
 * @Author Blueshadow
 * @Date 2021/7/31 15:28
 * @Version 1.0
 */
public class thread_exit {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.setName("王帥");
        t.setPriority(Thread.MIN_PRIORITY);//最小的優先順序
        t.start();//啟動子執行緒
        System.out.println("執行緒:"+t.getName()+"優先順序:"+t.getPriority());

        //主執行緒列印五個語句,然後就中斷子執行緒的休眠
        for (int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.println("Hello..."+i);
        }

        t.interrupt();//main 執行緒中斷
        System.out.println(Thread.currentThread().getName()+"...中斷");
    }
}
class T extends Thread{//自定義執行緒類

    @Override
    public void run() {
        while (true){
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName()+ "吃包子..." + i);
            }
            try {
                System.out.println(T.currentThread().getName() + "休眠中...");
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                //當該執行緒執行到一個interrupt方法時,就會catch一個異常,可以加入自己的業務程式碼
                //InterruptedException 捕獲到一箇中斷異常
                e.printStackTrace();
                System.out.println(Thread.currentThread().getName() + "被 interrupt");
            }
        }
    }
}

3.3執行緒插隊

package thread;
@SuppressWarnings({"all"})
/**
 * @Author Blueshadow
 * @Date 2021/7/31 15:28
 * @Version 1.0
 */
public class thread_exit {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.start();//啟動子執行緒
        //讓子執行緒插隊到main執行緒前面,這樣,main執行緒就會等子執行緒執行完畢再執行
        //如果沒有進行join,則主執行緒和子執行緒就會交替執行
        for (int i = 0; i <= 20 ; i++) {
            Thread.sleep(1000);
            System.out.println("主執行緒吃 "+ i +" 個包子");
            if (i == 5){
                System.out.println("*****主執行緒吃了五個*****");
                t.join();//插入執行緒,讓子執行緒執行完畢
            }
        }
    }
}

class T extends Thread{//自定義執行緒類

    @Override
    public void run() {
        for (int i = 0; i <= 20; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子執行緒吃了 " + i +" 個包子");//輸出子執行緒內容
        }
    }
}

3.4使用者執行緒和守護執行緒

使用者執行緒

也叫作工作執行緒,當執行緒的任務執行完或通知方式結束

守護執行緒

一般為工作執行緒服務,當所有的使用者執行緒結束,守護執行緒自動結束,常見的守護執行緒——垃圾回收機制

package thread;
@SuppressWarnings({"all"})
/**
 * @Author Blueshadow
 * @Date 2021/7/31 15:28
 * @Version 1.0
 */
public class thread_exit {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        //將t設定成守護執行緒,當main程序結束之後(即所有執行緒結束之後),t執行緒也自動結束
        t.setDaemon(true);
        t.start();//啟動子執行緒
        for (int i = 0; i <= 10 ; i++) {
            Thread.sleep(1000);
            System.out.println("Hello");
        }
    }
}

class T extends Thread{//自定義執行緒類

    @Override
    public void run() {
        for ( ; ; ) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("World");
        }
    }
}

4.執行緒生命週期

JDK中用Thread.State列舉表示了執行緒的幾種狀態

NEW	尚未啟動的執行緒

RUNNABLE	在Java虛擬機器中執行的執行緒

BLOCKED	被阻塞等監視器鎖定的執行緒

WAITING	正在等待另一個執行緒執行特定動作的執行緒

TIME_WAITING	正在等待另一個執行緒執行動作達到指定等待時間的執行緒

TERMINATED	已退出的執行緒

5.Synchronized(執行緒同步機制)

在多執行緒程式設計,一些敏感資料不允許被多個執行緒同時訪問,此時就使用同步訪問技術,保證資料在任何時刻,最多有一個執行緒訪問,以保證資料的完成性;

當有一個執行緒在對記憶體進行操作時,其他執行緒都不可以對這個記憶體地址進行操作,直到該執行緒完成操作,其他執行緒才能對該記憶體地址進行操作。