Java基礎 線程 & 線程池

線程

Java多線程三種實現方式

  • 自定義類繼承Thread類,重寫run()方法,new MyThread().start()
  • 自定義類實現Runnable接口,重寫run()方法,new Thread(new MyRunnable()).start()
  • 使用ThreadPoolExecutor線程池

Java線程狀態

NEW

新建狀態:線程創建完成,調用start()方法之前。

RUNNABLE

運行狀態:調用start()方法,線程由NEW狀態進入RUNNABLE狀態。
RUNNABLE狀態包含READY和RUNNING
READY狀態:等待CPU時間片。
RUNNING狀態:任務正在被CPU處理,調用yield()方法讓出CPU,線程由RUNNING狀態進入READY狀態。

BLOCKED

阻塞狀態:等待獲取重量級鎖。

WAITING

等待狀態:調用Object.wait()、Thread.join()、LockSupport.park()方法,線程由RUNNABLE狀態進入WAITING狀態,沒有時間限制。
Object.wait()對應調用Object.notify()或Object.notifyAll()方法,線程由WAITING狀態進入RUNNABLE狀態。
Thread.join()等待join的線程執行完,線程由WAITING狀態進入RUNNABLE狀態。
LockSupport.park()對應調用LockSupport.unpark(thread)方法,線程由WAITING狀態進入RUNNABLE狀態。

TIMED_WAITING

等待狀態:調用Thread.sleep(long)、Object.wait(long)、Thread.join(long)、LockSupport.parkNanos()、LockSupport.parkUntil()方法,線程由RUNNABLE狀態進入TIMED_WAITING狀態,有時間限制,超時回到RUNNABLE狀態。

TERMINATED

結束狀態:任務執行完成。
Thread.run()方法和Thread.start()方法
Thread.run()方法:只是方法調用,實際還是當前線程執行run()方法
Thread.start()方法:創建一個線程來執行run()方法
Thread.sleep()方法和Object.wait()方法
Thread.sleep()方法:可在任何地方使用,讓出CPU,不操作鎖
Object.wait()方法:只能在synchronized方法或synchronized代碼塊中使用,讓出CPU,釋放鎖

線程池

ThreadPoolExecutor()構造方法七個參數

corePoolSize:核心線程數
maximumPoolSize:最大線程數
keepAliveTime:線程空閒時間
unit:線程空閒時間單位
workQueue:阻塞隊列
threadFactory:創建線程的工廠
handler:拒絕策略
拒絕策略
AbortPolicy:默認策略,拋RejectedExecutionException異常
DiscardPolicy:什麼也不做
CallerRunsPolicy:該任務由調用者來處理
DiscardOldestPolicy:丟棄最早的任務,放入新任務
線程數量推薦設置
處理耗時任務,線程數 = CPU數量 * 2
處理密集任務,線程數 = CPU數量 + 1

Java線程池狀態

RUNNING

接受新任務,並處理隊列任務。

SHUTDOWN

不接受新任務,會處理隊列任務;調用shutdown()方法,線程池由RUNNING狀態進入SHUTDOWN狀態。

STOP

不接受新任務,不處理隊列任務,中斷正在處理的任務;調用shutdownNow()方法,線程池由RUNNING狀態進入STOP狀態。

TIDYING

所有任務結束,所有線程釋放,執行terminated()方法之前。

TERMINATED

terminated()方法執行完成,線程池由TIDYING狀態進入TERMINATED狀態。

線程池核心方法

execute

當前線程數 < 核心線程數:創建核心線程處理任務
當前線程數 >= 核心線程數 && 阻塞隊列未滿:任務添加至阻塞隊列
當前線程數 >= 核心線程數 && 阻塞隊列已滿 && 當前線程數 < 最大線程數:創建普通線程處理任務
當前線程數 >= 核心線程數 && 阻塞隊列已滿 && 當前線程數 = 最大線程數:執行拒絕策略

addWorker

addWorker(command,true):創建核心線程至workers集合,並處理任務;如果當前線程數 >= 核心線程數,返回false。
addWorker(command,false):創建普通線程至workers集合,並處理任務;如果當前線程數 = 最大線程數,返回false。
addWorker(null,true):創建核心線程至workers集合。
addWorker(null,false):創建普通線程至workers集合。

runWorker

調用Thread.start()方法處理任務。
Worker類繼承AQS類;非公平,通過CAS競爭鎖,通過LockSupport.park()和LockSupport.unpark(thread)方法控制線程狀態。

Executors提供的四種線程池

newFixedThreadPool
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

指定線程個數的線程池,生產環境常用這種線程池。由於阻塞隊列使用LinkedBlockingQueue,因此maximumPoolSize和handler參數無效。

newCachedThreadPool
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

緩存空閒線程的線程池,乍一看很不錯,符合複用的編程思想。阻塞隊列用SynchronousQueue,因此添加任務會馬上執行(如果有空閒線程,讓空閒線程執行;如果沒有空閒線程,則創建線程執行)。不適合執行耗時任務(IO),線程數不好控制,因此生產環境幾乎不用這種線程池。

newSingleThreadExecutor
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

只有一個線程的線程池,可以保證任務的執行順序;線程執行過程中異常,會重新創建一個線程繼續執行任務。

newScheduledThreadPool
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

執行週期任務的線程池,可以設置每過多久執行一次。
實現定時任務的方式有很多,如spring boot的@EnableScheduling,或者第三方定時任務框架,因此很少使用這種線程池。

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