天天看點

并發程式設計 -- 線程建構及線程狀态

文章目錄

  • ​​一.線程​​
  • ​​1.基本概念​​
  • ​​2.一個普通的java程式包括哪些線程​​
  • ​​二,建立線程​​
  • ​​1.繼承Thread類,重寫run方法​​
  • ​​2.實作Runnable接口,重寫run方法​​
  • ​​3.帶有傳回值的多線程實作 --- 實作callable接口​​
  • ​​4.基于線程池​​
  • ​​三,線程狀态​​
  • ​​1.狀态圖​​
  • ​​2.過程​​

一.線程

1.基本概念

  • 現代作業系統排程的最小單元是線程,也叫輕量級程序
  • 一個程序裡可以建立多個線程
  • 每一個線程都擁有各自的計數器,堆棧,局部變量表等屬性,并且可以通路共享的記憶體變量
  • 處理線上程之間告訴切換,使使用者感覺好像這些線程同時執行

2.一個普通的java程式包括哪些線程

一個java程式不僅僅是main主線程在運作,還有其他多個線程在同時運作,java程式本身就是一個多線程程式

@Slf4j
public class MultiThread {
    
    public static void main(String[] args) {
        // 擷取java線程管理MXBean
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        // 擷取線程和線程的堆棧資訊(不需要擷取線程的Monitors,synchronizers)
        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false,false);
        // 列印線程資訊
        for(ThreadInfo threadInfo:threadInfos){
            log.info("threadName:--------->"+threadInfo.getThreadName());
        }
    }
}      

控制台列印結果:

22:41:44.930 [main] INFO com.kevin.demo.base_of_cconcurrency.MultiThread - threadName:--------->Monitor Ctrl-Break
22:41:44.935 [main] INFO com.kevin.demo.base_of_cconcurrency.MultiThread - threadName:--------->Attach Listener 
22:41:44.935 [main] INFO com.kevin.demo.base_of_cconcurrency.MultiThread - threadName:--------->Signal Dispatcher
22:41:44.935 [main] INFO com.kevin.demo.base_of_cconcurrency.MultiThread - threadName:--------->Finalizer
22:41:44.935 [main] INFO com.kevin.demo.base_of_cconcurrency.MultiThread - threadName:--------->Reference Handler
22:41:44.935 [main] INFO com.kevin.demo.base_of_cconcurrency.MultiThread - threadName:--------->main      

各個基本線程的作用:

  • Monitor Ctrl-Break
  • Attach Listener : 線程的職責是接收外部jvm指令
  • signal dispather : 去進行分發處理發送給JVM各個不同的子產品處理指令
  • Finalizer :調用對象該方法的線程
  • Reference Handler :清除引用的線程
  • main :主線程

二,建立線程

1.繼承Thread類,重寫run方法

線程執行的任務放于run方法中

@Slf4j
public class NewThread1 extends Thread{

    @Override
    public void run() {
        while (true){
            log.info("-----> Thread1111111111111111");
        }
    }
}      

啟動線程,通過調用Thread類的start()方法來啟動一個線程。

// 線程建構方式一
        NewThread1 newThread1 = new NewThread1();
        newThread1.start();      

調用run()和調用start()方法有什麼不同?

  • 調用start方法是開啟一個新線程放入到等到隊列中,一旦争奪到cpu資源便開始執行
  • 調用子線程的run方法實際上并不會開啟一個新的線程,還是在主線程中

2.實作Runnable接口,重寫run方法

@Slf4j
public class NewThread2 implements Runnable{

    @Override
    public void run() {
        while(true){
            log.info("---------> newThread222222222222222");
        }
    }
}      

啟動線程,傳入runnable子類對象

// 線程建構方式二
        Thread thread = new Thread(new NewThread2());
        thread.start();      

3.帶有傳回值的多線程實作 — 實作callable接口

傳回值類型就是Callable中的泛型參數類型T

@Slf4j
public class NewThread3 implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int i = 0;
        while(i<10000){
            log.info("--------> newThread333333333333");
            i++;
        }
        return i;
    }
}      

注意,這裡跟前面兩種方式的不同之處在于要借助一個中間類FutureTask

// 線程建構方式三
        FutureTask futureTask = new FutureTask(new NewThread3());
        Thread thread3 = new Thread(futureTask);
        thread3.start();

        //擷取傳回值
        int i = (int) futureTask.get();
        log.info("-------> "+i);      

4.基于線程池

使用線程池可以降低資源消耗,提高響應速度和線程的可管理性

之後會另外總結

@Slf4j
public class NewThead4 {

    public static void main(String[] args) {
        // 建立線程池
        ExecutorService executorService = new ThreadPoolExecutor(5, 10, 500,
                TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5));

        //執行任務
        while (true) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("------------>newThread444444444444444");
                }
            });
        }
    }
}      

測試結果:

并發程式設計 -- 線程建構及線程狀态

線程之間在互相争奪cpu資源,誰搶到誰執行

三,線程狀态

1.狀态圖

2.過程

  1. 線程建立
  2. 調用start()開始進入運作狀态,但是此時并非馬上就運作任務,需要等到系統cpu配置設定到目前線程資源才能執行任務,Thread.yield()方法作用是:暫停目前正在執行的線程對象(及放棄目前擁有的cup資源),并執行其他線程。
  3. 線程如果執行正常,将直接完成目前周期
  4. 若線程執行wait(),則進入等待狀态,在這一狀态中,需要依靠其他線程的通知(喚醒)才能傳回運作狀态
  5. 還有個就是逾時等待狀态,跟等待狀态不同的是,逾時等待狀态經過指定時間就可以自動傳回運作狀态
  6. 阻塞,當線程遇到同步方法或者同步代碼塊,則進入阻塞狀态