一.多線程創建方式
1.繼承thread類
//繼承Thread類來創建線程
public class ThreadTest {
public static void main(String[] args) {
//設置線程名字
Thread.currentThread().setName("thread");
MyThread myThread = new MyThread();
myThread.setName("子線程:");
//開啓線程
myThread.start();
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName() + i);
}
}
}
class MyThread extends Thread{
//重寫run()方法
public void run(){
for(int i=0;i<10; i++){
System.out.println(Thread.currentThread().getName() + i);
}
}
}
2.實現Runable接口
//實現Runnable接口
public class RunnableTest {
public static void main(String[] args) {
//設置線程名字
Thread.currentThread().setName("thread:");
Thread thread = new Thread(new MyRunnable());
thread.setName("子線程:");
//開啓線程
thread.start();
for(int i=0; i<10;i++){
System.out.println(Thread.currentThread().getName() + i);
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i=0; i<10; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
}
3.實現Callable接口(有回調)
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//實現Callable接口
public class CallableTest {
public static void main(String[] args) {
//執行Callable 方式,需要FutureTask 實現實現,用於接收運算結果
FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyCallable());
new Thread(futureTask).start();
//接收線程運算後的結果
try {
Integer sum = futureTask.get();
System.out.println(sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i=0; i<10; i++) {
sum += i;
}
return sum;
}
}
4.線程池創建
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//線程池實現
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
//創建線程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
ThreadPool threadPool = new ThreadPool();
for(int i =0;i<5;i++){
//爲線程池分配任務
executorService.submit(threadPool);
}
//關閉線程池
executorService.shutdown();
}
}
class ThreadPool implements Runnable {
@Override
public void run() {
for(int i=0 ;i<10;i++){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
二.常用線程池
1.newFixedThreadPool
創建一個指定工作線程數量的線程池。每當提交一個任務就創建一個工作線程,如果工作線程數量達到線程池初始的最大數,則將提交的任務存入到池隊列中。
newFixedThreadPool是一個典型且優秀的線程池,它具有線程池提高程序效率和節省創建線程時所耗的開銷的優點。但是,在線程池空閒時,即線程池中沒有可運行任務時,它不會釋放工作線程,還會佔用一定的系統資源。
2.newCachedThreadPool
創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閒線程,若無可回收,則新建線程。
這種類型的線程池特點是:
(1)工作線程的創建數量幾乎沒有限制(其實也有限制的,數目爲Interger. MAX_VALUE), 這樣可靈活的往線程池中添加線程。
如果長時間沒有往線程池中提交任務,即如果工作線程空閒了指定的時間(默認爲1分鐘),則該工作線程將自動終止。終止後,如果你又提交了新的任務,則線程池重新創建一個工作線程。
(2)在使用newCachedThreadPool時,一定要注意控制任務的數量,否則,由於大量線程同時運行,很有會造成系統癱瘓。
3.newSingleThreadExecutor
創建一個單線程化的Executor,即只創建唯一的工作者線程來執行任務,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO,優先級)執行。如果這個線程異常結束,會有另一個取代它,保證順序執行。單工作線程最大的特點是可保證順序地執行各個任務,並且在任意給定的時間不會有多個線程是活動的。
4.newScheduleThreadPool
創建一個定長的線程池,而且支持定時的以及週期性的任務執行,支持定時及週期性任務執行。
三.線程池七大核心參數
1.corePoolSize(核心線程數)
2.maxPoolSize(最大線程數)
3.keepAliveTime(空閒回收時間)
4.unit(回收時間單位)
5.workQueue(任務隊列)
6.threadFactory(線程工廠,用於創建線程,一般爲默認線程工廠即可)
7.handler(拒絕策略)
當調用 execute(()方法添加一個請求任務時,線程池會做如下判斷::
當創建線程任務數小於核心線程數corePoolSize時則直接創建執行,當創建線程任務數大於核心線程數時則加入任務隊列workQueue中
(常用的任務隊列有 有界隊列:1.ArrayBlockingQueue,2.SynchronousQueue,
無界隊列:1.LinkedBlockingQueue,暫不詳述。)等待,
當任務隊列也放滿之後查看是否大於最大線程數maxPoolSize,如果這時候隊列滿了且正在運行的線程數量還小於 naximumPoolSize,,那麼還是要創建非核心線程立刻運行這個任務,如果大於最大線程數則執行拒絕策略handler
(拒絕策略有分爲四種:
1. CallerRunsPolicy :這個策略重試添加當前的任務,他會自動重複調用 execute() 方法,直到成功。
2. AbortPolicy :對拒絕任務拋棄處理,並且拋出異常。
3. DiscardPolicy :對拒絕任務直接無聲拋棄,沒有異常信息。
4. DiscardOldestPolicy :對拒絕任務不拋棄,而是拋棄隊列裏面等待最久的一個線程,然後把拒絕任務加到隊列。
)如果沒有則創建執行。當一個線程完成任務時,它會從隊列中取下一個任務來執行。當一個線程無事可做超過一定的時間( keepAliveTime))時,線程池會判斷:如果當前運行的線程數大於 corePoolSize,,那麼這個線程就被停掉。所以線程池的所有任務完成後它最終會收縮到 corePoolSize的大小。