1. 程式人生 > 其它 >執行緒介紹,常用方法,生命週期,執行緒守護,執行緒同步機制,互斥鎖,執行緒死鎖相關概念

執行緒介紹,常用方法,生命週期,執行緒守護,執行緒同步機制,互斥鎖,執行緒死鎖相關概念

一、引入概念

程式:是為完成特定任務、用某種語言編寫的一組指令的集合。簡單的說:就是我們寫的程式碼

程序:

1、程序是指執行中的程式

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

執行緒:

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

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

單執行緒和多執行緒:

單執行緒:同一個時刻,只允許執行一個執行緒

多執行緒:同一時刻,可以執行多個執行緒

併發和並行:

二、執行緒的繼承實現圖;(自定義執行緒可以繼承Thread也可以直接實現Rubable)

(1)繼承Thread實現一個簡單的執行緒

public class
Thread01 { public static void main(String[] args) { cat cat = new cat();
      cat.run();//run只是在cat中的一個方法,當呼叫時,並不會重新開啟一個執行緒。會在main中按照順序執行
      cat.start();//啟動執行緒,啟動之後run方法開始執行,並不會對main方法造成任何影響。
} }
class cat extends Thread{ @Override public void run() { int runtime = 0; while (runtime<8) {
try { System.out.println("喵喵,我是小貓咪!"); runtime++; Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }

執行緒的結構

可以在程式執行時(程序開始的時候:在終端利用Jconsole檢視當前程序中的執行緒)

注意:

在程序中,如果主執行緒停止了,子執行緒還沒結束,並不會結束程序。

(2)實現一個Runnabled的介面,實現一個多執行緒的類

public class Thread02 {
    public static void
main(String[] args) { dog dog = new dog(); //dog.start(); Thread thread = new Thread(dog); thread.start(); } } class dog implements Runnable{ @Override public void run() { int timesize = 0; while (timesize<10) { try { System.out.println("hi! here is a dog!!!"); timesize++; Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }

注意:由於沒有繼承Thread類,所以在main中無法呼叫start方法啟動執行緒,Runnable中只有一個run方法,所以需要重新定義一個新的執行緒,再將實現類dog放進去;

(3)執行緒的的基本使用

<1>執行緒如何理解:

(4)執行緒終止

基本說明:

1.當執行緒完成任務後,會自動退出。
2.還可以通過使用變數來控制run方法退出的方式停止執行緒,即通知方式

(利用一個loop來通知執行緒結束)

public class Thread02 {
    public static void main(String[] args) throws InterruptedException {

        dog dog = new dog();
        //dog.start();

         Thread thread = new Thread(dog);
         thread.start();

         Thread.sleep(10*1000);

         dog.setLoop(false);
    }
}
class dog implements  Runnable{

    private boolean loop = true;

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

    @Override
    public void run() {

        int timesize = 0;


        while (loop) {
            try {
                System.out.println("hi! here is a dog!!!");
                timesize++;
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

(5)執行緒常用方法

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

2).getName//返回該執行緒的名稱
3). start//使該執行緒開始執行;Java虛擬機器底層呼叫該執行緒的startO方法

4). run 1/呼叫執行緒物件run 方法;
5).setPriority //更改執行緒的優先順序

6). getPriority //獲取執行緒的優先順序
7).sleep1/在指定的毫秒數內讓當前正在執行的執行緒休眠(暫停執行)
8). interrupt 1/中斷執行緒

9)yield:執行緒的禮讓。讓出cpu,讓其他執行緒執行,但禮讓的時間不確定,所以也不一定禮讓成功

10).join: 執行緒的插隊。插隊的執行緒一旦插隊成功,則肯定先執行完插入的執行緒所有的任務

程式碼例項:

public class ThreadMothed {
    public static void main(String[] args) throws InterruptedException {

        T t = new T();
        t.start();//啟動執行緒
        for (int i = 0; i <10; i++) {//進行主執行緒的程式碼執行
            Thread.sleep(1000);
            System.out.println("here is main!!"+i);
            if (i == 3){
                System.out.println("開始插隊!!");
                t.join();//讓T插隊,插隊之後t執行緒將執行完畢退出再進入主程式
                System.out.println("插隊完成!!");
            }
        }

    }
}
class T extends Thread{
    @Override
    public void run() {

        int i = 0;
        while (i<10){
            try {
            for (int j = 0; j < 10; j++) {
                Thread.sleep(1000);
                System.out.println("hello test let`s go!!"+ j);
                i++;
            }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

11)使用者執行緒和守護執行緒

1.使用者執行緒:也叫工作執行緒,當執行緒的任務執行完或通知方式結束
2.守護執行緒:一般是為工作執行緒服務的,當所有的使用者執行緒結束,守護執行緒自動結束

3.常見的守護執行緒:垃圾回收機制

public class ThreadMothed01 {
    public static void main(String[] args) throws InterruptedException {
        T1 t1 = new T1();
        Thread thread = new Thread(t1);
        thread.setDaemon(true);//設定執行緒為守護執行緒
        thread.start();
        for (int i = 0; i < 5; i++) {
            System.out.println("test deamon!!!");
            Thread.sleep(1000);
        }
    }
}

class T1 implements Runnable{
    @Override
    public void run() {

        int i = 0;
//        while (i < 10) {
        while (true) {//測試守護執行緒
            for (int j = 0; j < 10; j++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("test!!!" + j);
                i++;
            }
        }
    }
}

二、執行緒的生命週期

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

執行緒狀態圖

三、執行緒同步機制(Synchronized)

執行緒同步機制:

1.在多執行緒程式設計,一些敏感資料不允許被多個執行緒同時訪問,此時就使用同步訪問技
術,保證資料在任何時刻,最多有一個執行緒訪問,以保證資料的完整性。
2.也可以這裡理解:執行緒同步,即當有一個執行緒在對記憶體進行操作時,其他執行緒都不
可以對這個記憶體地址進行操作,直到該執行緒完成操作,其他執行緒才能對該記憶體地址進行操作.

同步具體方法:

四、互斥鎖

基本介紹:

1. Java語言中,引入了物件互斥鎖的概念,來保證共享資料操作的完整性。
2.每個物件都對應於一個可稱為“互斥鎖”的標記,這個標記用來保證在任一時刻,只能有一個執行緒訪問該物件。
3.關鍵字synchronized來與物件的互斥鎖聯絡。當某個物件用synchronized修飾時,表明該物件在任一時刻只能由一個執行緒訪問
4.同步的侷限性:導致程式的執行效率要降低
5.同步方法(非靜態的)的鎖可以是this,也可以是其他物件(要求是同一個物件)

6.同步方法(靜態的)的鎖為當前類本身。

public class selltickets {
    public static void main(String[] args) {

//        Tickets tickets = new Tickets();
//        Tickets tickets1 = new Tickets();
//        Tickets tickets2 = new Tickets();
//        tickets.start();

        

        //定義三個新執行緒,開始進行執行緒同步測試,執行緒處理的物件需要是同一個物件
        //不然不會體現出執行緒同步,執行緒鎖的作用
        Tickets tickets = new Tickets();
         new Thread(tickets).start();
         new Thread(tickets).start();
         new Thread(tickets).start();

    }
}
class Tickets extends Thread{
//class Tickets implements Runnable{
    private int ticket = 100;
    private boolean loop = true;
    @Override
    public  void run() {
        while (loop){
            loop=sell();
        }
    }
    private  synchronized boolean sell(){
        if (ticket<=0){
            System.out.println("票已全部售出。。。");
            return false;
        }
        if (ticket>0){
            System.out.println(Thread.currentThread().getName() + "-售出一張票-剩餘的票數"+(--ticket));
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return  true;
    }
}

注意事項和細節:

1.同步方法如果沒有使用static修飾:預設鎖物件為this

2.如果方法使用static修飾,預設鎖物件:當前類.class
3.實現的落地步驟:
需要先分析上鎖的程式碼

選擇同步程式碼塊或同步方法
要求多個執行緒的鎖物件為同一個即可!

五、執行緒死鎖

簡介:多個執行緒都佔用了對方的鎖資源,但不肯相讓,導致了死鎖,在程式設計是一定要避免死鎖的發生。

(1)使用繼承方式Thread 體現死鎖

public class DeadLock {
    public static void main(String[] args) {

        Lock lock = new Lock(true);//傳參true獲取o1物件
        lock.setName("true");//設定執行緒名稱
        Lock lock1 = new Lock(false);//傳參true獲取o2物件
        lock1.setName("false");
        //開始新的程序
        lock.start();
        lock1.start();
    }
}

class Lock extends Thread {
    static Object o1 = new Object();
    static Object o2 = new Object();
    private boolean loop;

    public Lock(boolean loop) {
        this.loop = loop;
    }

    @Override
    public void run() {
        if (loop){
            synchronized (o1){
                System.out.println(Thread.currentThread().getName()+"進入正確的o1,等待o2");
                synchronized (o2){
                    System.out.println("拿到o2,o1執行完成");
                }
            }
        }else{
            synchronized (o2){
                System.out.println(Thread.currentThread().getName()+"進入錯誤的o1,等待o2");
                synchronized (o1){
                    System.out.println("拿到o2,o1執行完成");
                }
            }
        }

    }
}

使用實現Runnable 的方式體現死鎖

public class DeadLock {
    public static void main(String[] args) {

        Lock lock = new Lock(true);
        Thread thread = new Thread(lock);
        thread.setName("A");
        Lock lock1 = new Lock(false);
        Thread thread1 = new Thread(lock1);
        thread1.setName("B");
        thread.start();
        thread1.start();

    }
}

class Lock implements Runnable {
    static Object o1 = new Object();
    static Object o2 = new Object();
    private boolean loop;

    public Lock(boolean loop) {
        this.loop = loop;
    }

    @Override
    public void run() {
        if (loop){
            synchronized (o1){
                System.out.println(Thread.currentThread().getName()+"進入正確的o1,等待o2");
                synchronized (o2){
                    System.out.println("拿到o2,o1執行完成");
                }
            }
        }else{
            synchronized (o2){
                System.out.println(Thread.currentThread().getName()+"進入錯誤的o1,等待o2");
                synchronized (o1){
                    System.out.println("拿到o2,o1執行完成");
                }
            }
        }

    }
}

六、釋放鎖

釋放鎖的情況:

1.當前執行緒的同步方法、同步程式碼塊執行結束
案例:上廁所,完事出來
2.當前執行緒在同步程式碼塊、同步方法中遇到break、return.
案例:沒有正常的完事,經理叫他修改bug,不得已出來
3.當前執行緒在同步程式碼塊、同步方法中出現了未處理的Error或Exception,導致異常結束
案例:沒有正常的完事,發現忘帶紙,不得已出來
4.當前執行緒在同步程式碼塊、同步方法中執行了執行緒物件的wait()方法,當前執行緒暫停,並釋
放鎖。
案例:沒有正常完事,覺得需要醞釀下,所以出來等會再進去

不會釋放鎖的情況:

1.執行緒執行同步程式碼塊或同步方法時,程式呼叫Thread.sleep()、Thread.yield()方
法暫停當前執行緒的執行,不會釋放鎖
案例:上廁所,太困了,在坑位上眯了一會
2.執行緒執行同步程式碼塊時,其他執行緒呼叫了該執行緒的suspend()方法將該執行緒掛起,
該執行緒不會釋放鎖。
提示:應儘量避免使用suspend()和resume()來控制執行緒,方法不再推薦使用