1. 程式人生 > >【java多執行緒】執行緒常用操作方法總結

【java多執行緒】執行緒常用操作方法總結

文章目錄


多執行緒的主要操作方法都在Thread類中定義了。

執行緒的命名與獲取

      多線的的執行狀態是不確定的,那麼在程式的開發之中為了可以獲取一些需要使用執行緒就只能夠依靠執行緒的名字來進行操作。所以執行緒的名字是一個至關重要的概念,這樣在Thread類之中就提供有執行緒名稱的處理:

  • 建構函式
    public Thread (Runnable target,String name);
  • 設定名字public final void setName(String name);
  • 取得名字: public final String getName();
          對於執行緒物件的獲得是不可能只是依靠一個this來完成的,因為執行緒的狀態不可控,但是有一點是明確的,所有的執行緒一定要執行run()方法,難麼這個時候可以考慮獲取當前執行緒,在Tread類中有獲取執行緒的方法:
  • 獲取當前執行緒: public static Thread currentThread();

範例: 觀察執行緒的命名操作

class MyThread implements Runnable {//執行緒主體類
    @Override
    public void run() {//執行緒的主體方法
        System.out.println(Thread.currentThread().getName());
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        MyThread mt  = new MyThread();
        new Thread(mt,"執行緒A").start();
        new Thread(mt).start();
        new Thread(mt,"執行緒B").start();
    }
}

      當開發者為執行緒設定名字的時候就使用這個設定的名字,而如果沒有設定名字就自動生成一個不重複的名字,這種自動的屬性命名主要是依靠static屬性完成的,在Thread類裡面有定義如下操作:

  private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }

範例:觀察一個程式的執行

class MyThread implements Runnable {//執行緒主體類
    @Override
    public void run() {//執行緒的主體方法
        System.out.println(Thread.currentThread().getName());
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        MyThread mt  = new MyThread();
        new Thread(mt,"執行緒A").start();
        mt.run();
    }
}

輸出結果:

main
執行緒A

      通過此時的程式碼可以發現當使用了“mt.run()”直接在主方法之中呼叫執行緒類物件中的run()方法,所獲得的執行緒的名字為“main”,所以可以的得出一個結論:主方法也是一個執行緒,那麼現在的問題來了,所有的執行緒都是在程序上的一個劃分,那麼程序在哪裡?每當使用java命令執行程式的時候就表示啟動了一個JVM的程序,一臺電腦上可以啟動若干個JVM程序,所以JVM的程序都會有個自的執行緒。
在這裡插入圖片描述
      在任何的開發之中,主執行緒可以建立若干個子執行緒,建立子執行緒的目的是可以將一些複雜邏輯或者比較耗時的程式處理:

範例:子執行緒的處理

public class ThreadDemo {
    public static void main(String[] args) {
        System.out.println("1、執行操作任務一");
        new Thread(() -> {
            int temp = 0;
            for(int x = 0 ; x < 10 ; x ++) {
                temp += x;
                System.out.println(temp);
            }
        }).start();
        System.out.println("2、執行操作任務二");
        System.out.println("N、執行操作任務N");
    }
}

主執行緒負責處理整體流程,而子執行緒負責處理耗時操作。

執行緒休眠

      如果說現在希望某一個執行緒可以暫緩執行,那麼就可以使用休眠的處理,在Thread中定義的休眠方法如下:

  • 休眠: public static void sleep(long millis) throws InterruptedException;
  • 休眠: public static void sleep(long millis,int nanos)throws InterruptedException;
          在進行休眠的時候,有可能會產生中斷異常“InterruptedException”,中斷異常屬於Exception的子類,所以該異常必須進行處理。

範例: 觀察休眠處理

public class ThreadDemo {
    public static void main(String[] args) {
        new Thread(() -> {
            for(int x = 0 ; x < 10 ; x ++) {
                System.out.println(Thread.currentThread().getName() + "、x = " + x);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        },"執行緒物件").start();
    }
}

      休眠的主要特點是可以自動實現執行緒的喚醒,以繼續進行後續的處理。但是需要注意的是,如果現在有多個執行緒物件,休眠也是有多個先後順序的。

**範例:**產生多個執行緒物件進行休眠處理。

public class ThreadDemo {
    public static void main(String[] args) {
        for( int i = 0; i < 5; i ++) {
            new Thread(() -> {
                for(int x = 0 ; x < 10 ; x ++) {
                    System.out.println(Thread.currentThread().getName() + "、x = " + x);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            },"執行緒物件 - " + i).start();
        }

    }
}

      此時將產生五個執行緒物件,並且這五個執行緒物件執行的方法體是相同的。此時從程式執行的感覺上來看是一起進行了休眠,而後一起進行了自動喚醒,但是實際上是有差別的。
在這裡插入圖片描述

執行緒中斷

      在之前發現執行緒的休眠裡面提供有一箇中斷異常,實際上就證明執行緒的休眠是可以打斷的,而這種打斷肯定是由其他執行緒完成的,在Thread類裡面提供有這種中斷執行的方法:

  • 判斷執行緒是否被中斷: public boolean isInterrupted();
  • 中斷執行緒執行: public void interrupt();

**範例:**觀察執行緒的中斷處理操作

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println("*** 狂歡了72小時我需要睡覺");
            try {
                Thread.sleep(10000);  //睡眠10秒
                System.out.println("睡足了,要繼續初五禍害別人");
            } catch (InterruptedException e) {
                System.out.println("敢打擾老子睡覺,宰了你");
            }

        });
        thread.start();
        Thread.sleep(1000);
        if( !thread.isInterrupted()) {
            System.out.println("打擾你一下");
            thread.interrupt();
        }
    }
}

      所有正在執行的執行緒都是可以被中斷的,中斷執行緒必須進行異常處理。

執行緒強制執行

      所謂的執行緒的強制執行,指的當滿足某些條件之後,某一個執行緒物件將一直可以獨佔資源,一直到該執行緒的程式執行結束。
範例: 觀察一個沒有被強制執行的程式

public class TestThread {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
           for(int x = 0 ; x < 100 ; x ++) {
               System.out.println(Thread.currentThread().getName() + "、 x = " + x);
           }
        },"玩耍的執行緒");
        thread.start();
        for(int x = 0; x < 100; x ++) {
            System.out.println("【霸道的main主執行緒】 x = "+ x);
        }
    }
}

       這個時候主執行緒和子執行緒都在交替執行著,但是如果你希望主線獨佔執行。那麼就是利用Thread類中方法強制執行。

  • 強制執行:public final void join()throws InterruptedException;
    範例: 強制執行的程式碼示例
public class TestThread {
    public static void main(String[] args) {
        Thread mainThread = Thread.currentThread(); //獲得主執行緒
        Thread thread = new Thread(() -> {
           for(int x = 0 ; x < 100 ; x ++) {
               if(x == 3) {  //如果x == 3,就強制執行主執行緒
                   try {
                       mainThread.join();
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }
               System.out.println(Thread.currentThread().getName() + "、 x = " + x);
           }
        },"玩耍的執行緒");
        thread.start();
        for(int x = 0; x < 100; x ++) {
            System.out.println("【霸道的main主執行緒】 x = "+ x);
        }
    }
}

      在進行執行緒強制執行的時候,一定要獲取強制執行執行緒物件之後才可以執行join()的呼叫。

執行緒禮讓

      執行緒的禮讓指的是先將執行緒的資源讓出去,讓別的執行緒先執行。執行緒的禮讓可以使用Thread中提供的方法:

  • 禮讓: public static void yield();

**範例:**使用禮讓操作

public class TestThread {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for(int x = 0 ; x < 100 ; x ++) {
                if(x % 3 == 0){
                    Thread.yield(); //執行緒禮讓
                    System.out.println("玩耍執行緒禮讓執行 ***********************");
                }
                System.out.println(Thread.currentThread().getName() + "、 x = " + x);
            }
        },"玩耍的執行緒");
        thread.start();
        for(int x = 0; x < 100; x ++) {
            System.out.println("【霸道的main主執行緒】 x = "+ x);
        }
    }
}

      禮讓執行的時候每一次呼叫yield()方法都只會禮讓一次當前資源。

執行緒優先順序

      從理論上來講,執行緒的優先順序越高越有可能先執行(越有可能先搶佔到資源)。在Thread類李曼針對優先順序的操作有兩個操作方法:

  • 設定優先順序:public final void setPriority(int newPriority);
  • 獲取優先順序:public final int getPriority();
          在進行優先順序定義的時候都是通過int型的數字來完成的,而對於此數字的選擇在Thread類裡面就定義有三個常量:
  • 最高優先順序: public static final int MAX_PRIORITY;(10)
  • 中等優先順序: public static final int NORM_PRIORITY;(5)
  • 最低優先順序: public static final int MIN_PRIORITY;(1)

範例:觀察優先順序

public class ThreadDem {
    public static void main(String[] args) {
         Runnable run = () ->{
             for(int x = 0; x < 100; x ++) {
                 System.out.println(Thread.currentThread().getName() + "、 x = " + x);
             }
         };
        Thread threadA = new Thread(run,"執行緒物件A");
        Thread threadB = new Thread(run,"執行緒物件B");
        Thread threadC = new Thread(run,"執行緒物件C");
        threadA.setPriority(Thread.MIN_PRIORITY);
        threadB.setPriority(Thread.MIN_PRIORITY);
        threadC.setPriority(Thread.MAX_PRIORITY);
        threadA.start();
        threadB.start();
        threadC.start();
    }
}

      主方法值一個主執行緒,那麼主執行緒的優先順序呢?

public class ThreadDem {
    public static void main(String[] args) {
        System.out.println("預設執行緒的優先順序:" + new Thread().getPriority());
        System.out.println("主方法執行緒優先順序:" + Thread.currentThread().getPriority());
}
}

輸出結果:

預設執行緒的優先順序:5
主方法執行緒優先順序:5

**      主執行緒是屬於中等優先順序,而預設建立的執行緒也是中等優先順序。
**