線程
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,或者第三方定時任務框架,因此很少使用這種線程池。