併發編程基礎

創建線程的方式

創建線程一般通過繼承Thread、實現Runnable接口、ExecutorService、Callable和Future等多種方式。

Thread實現

package all;
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("測試Thread");
    }
    public static void main(String[] args) {
        MyThread myThread1 = new MyThread();
        myThread1.start();
        MyThread myThread2 = new MyThread();
        myThread2.start();
    }
}

Runnable實現

package all;
public class MyRunnable implements Runnable {
    private volatile int i =5;
    @Override
    public void run() {
        while (i > 0){
            System.out.println("Runnable測試");
            --i;
        }
    }
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
        Thread thread1 = new Thread(myRunnable);
        thread1.start();
    }
}

Callable和FutureTask

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class MyCallable implements Callable<String> {

    public String call() throws Exception {
        return "TestCallable";
    }
    public static void main(String[] args) throws Exception {
        FutureTask<String> futureTask = new FutureTask(new MyCallable());
        futureTask.run();
        if(futureTask.isDone()){
            System.out.println(futureTask.get());
        }
    }
}

線程的生命週期

1.NEW:初始狀態,線程被創建,但是還沒有調用start方法
2.RUNNABLE:運行狀態,JAVA 線程把操作系統中的就緒和運行兩種狀態統一稱爲“運行中”
3.BOLCKED:阻塞狀態,表示線程進入等待狀態,也就是線程因爲某種原因放棄了 CPU 使用權,阻塞也分爲幾種情況
-->等待阻塞:運行的線程執行 wait 方法,jvm 會把當前線程放入到等待隊列
-->同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被其他線程鎖佔用了,那麼jvm會把當前的線程放入到鎖池中
-->其他阻塞:運行的線程執行 Thread.sleep 或者 t.join 方法,或者發出了I/O請求時,JVM 會把當前線程設置爲阻塞狀態,當 sleep 結束、join線程終止、io處理完畢則線程恢復
4.TIME_WAITING:超時等待狀態,超時以後自動返回
5.TERMINATED:終止狀態,表示當前線程執行完畢 

在這裏插入圖片描述

代碼演示:

import java.util.concurrent.TimeUnit;
public class ThreadTest {
    public static void main(String[] args) {
        //TIME_WAITING
        new Thread(()->{
            while (true){
                try {
                    TimeUnit.SECONDS.sleep(1000);
                }catch (InterruptedException ex){
                    ex.fillInStackTrace();
                }
            }
        },"測試Time_Waiting").start();

        //WAITING
        new Thread(()->{
            while (true){
               synchronized (ThreadTest.class){
                   try {
                       ThreadTest.class.wait();
                   }catch (InterruptedException ex){
                       ex.fillInStackTrace();
                   }
               }
            }
        },"測試WAITING").start();

        new Thread(new BlockedDemo(),"BlockedDemo01").start();
        new Thread(new BlockedDemo(),"BlockedDemo02").start();
    }
}
class BlockedDemo extends Thread{

    public void run(){
        synchronized (BlockedDemo.class){
            while(true){
                try {
                    TimeUnit. SECONDS .sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
通過idea終端輸入jps查到線程進程,使用jstack 進程查看堆棧信息

終止線程(Interrupt)

其它線程通過調用當前線程的Thread.Interrupt()方法向當前線程發送一個信號,告訴它可以中斷線程的執行了,至於什麼時候中斷,取決於當前線程自己。
判斷線程是否中斷可以使用Thread.currentThread().isInterrupted()來實現。

下面是一個例子:

package all;
public class ThreadTest {
    private static int i;
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(()->{
            //默認狀態是false,
            while(!Thread.currentThread().isInterrupted()){
                i++;
            }
            System.out.println("Num:"+i+",isInterrupted:"+Thread.currentThread().isInterrupted());
        },"測試線程");
        thread.start();
        Thread.sleep(1);
        //發送中斷標識,isInterrupted賦值true
        thread.interrupt();  //可以註釋掉試試效果
    }
}

執行結果:

Num:7124,isInterrupted:true
Process finished with exit code 0

線程的復位

線程的中斷就是通過Thread.Interrupt()方法把isTerrupted的值從false改爲true,但是中斷把值改爲true以後什麼也沒有做,是不是應該恢復到原始值呢,恢復原始值就是線程的復位通過Thread.interrupted,這只是我的個人理解。

通過同一個代碼對比一下:

package all;
public class ThreadTest {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(()->{
            while(true){
                //初始值是flase
               if(Thread.currentThread().isInterrupted()){
                   System.out.println("復位前的值:"+Thread.currentThread().isInterrupted());
                   Thread.interrupted();
                   System.out.println("復位後的值:"+Thread.currentThread().isInterrupted());
               }
            }
        },"測試線程Thread.interrupted()");
        thread.start();
        Thread.sleep(1);
        thread.interrupt(); //發送中斷標識賦值爲true
    }
}

執行結果:

復位前的值:true
復位後的值:false

爲什麼要復位

Thread.interrupted()是屬於當前線程的,是當前線程對外界中斷信號的一個響應,表示自己已經得到了中斷信號,
但不會立刻中斷自己,具體什麼時候中斷由自己決定,讓外界知道在自身中斷前,他的中斷狀態仍然是 false,這就
是復位的原因。

線程的啓動原理

在這裏插入圖片描述

從圖中可以看出start方法會通過JVM創建一個線程,然後回調run方法,等於是主線程和新創建的線程一起執行。
run方法沒有創建怎麼線程只有一個主線程等於同步執行。

總結圖

在這裏插入圖片描述

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