初始化線程的4種方式:
1、繼承Thread
public class TestThread extends Thread {
@Override
public void run() {
System.out.println("當前線程:" + Thread.currentThread().getName());
int i = 10 / 2;
System.out.println("運行結(jié)果:" + i);
}
public static void main(String[] args) {
System.out.println("main start");
TestThread testThread = new TestThread();
//啟動線程
testThread.start();
System.out.println("main end");
}
}
main start
main end
當前線程:Thread-0
運行結(jié)果:5
2、實現(xiàn)Runnable接口
public class TestThread2 implements Runnable{
public void run() {
System.out.println("當前線程:" + Thread.currentThread().getName());
int i = 10 / 2;
System.out.println("運行結(jié)果:" + i);
}
public static void main(String[] args) {
System.out.println("main start");
TestThread2 testThread = new TestThread2();
//啟動線程
new Thread(testThread).start();
System.out.println("main end");
}
}
main start
main end
當前線程:Thread-0
運行結(jié)果:5
實際上Thread類也是實現(xiàn)了Runnable接口
3、實現(xiàn)Callable接口+FutureTask(可以得到返回結(jié)果 ,可以處理異常,jdk1.5以后提供)
public class TestThread3 implements Callable<Integer> {
public Integer call() throws Exception {
System.out.println("當前線程:" + Thread.currentThread().getName());
int i = 10 / 2;
System.out.println("運行結(jié)果:" + i);
return i;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main start");
FutureTask<Integer> futureTask = new FutureTask<>(new TestThread3());
new Thread(futureTask).start();
//阻塞等待整個線程執(zhí)行完成,獲取返回結(jié)果
Integer result = futureTask.get();
System.out.println("返回結(jié)果:"+result);
System.out.println("main end");
}
}
main start
當前線程:Thread-0
運行結(jié)果:5
返回結(jié)果:5
main end因為要阻塞等待線程返回結(jié)果,所以主線程最后才結(jié)束
在業(yè)務代碼里面,以上三種啟動線程的方式都不用,應該將所有的異步任務都交給線程池執(zhí)行
4、線程池
創(chuàng)建簡單線程池的4種方式:
ExecutorService service = Executors.newFixedThreadPool();
該方法返回一個固定線程數(shù)量的線程池。該線程池中線程數(shù)量始終 不變。當有一個新的任務提交時,線程池中若有空閑線程,則立即執(zhí)行。若沒有,則新的任務會被暫存在一個任務隊列中,待有線程空閑時,便處理任務隊列中的任務。
缺點:它會創(chuàng)建一個Integer.MAX_VALUE長度的阻塞隊列。
ExecutorService service1 = Executors.newSingleThreadExecutor();
創(chuàng)建一個單線程的線程池,它只會用唯一一個工作線程來執(zhí)行任務
缺點:它會創(chuàng)建一個Integer.MAX_VALUE長度的阻塞隊列。
ExecutorService service2 = Executors.newCachedThreadPool();
創(chuàng)建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程。
缺點:它的最大線程數(shù)量為Integer.MAX_VALUE
ExecutorService service1 = Executors.newScheduledThreadPool()
創(chuàng)建一個定長線程池,支持定時及周期性任務執(zhí)行。
缺點:它的最大線程數(shù)量為Integer.MAX_VALUE
public class TestThread4 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//使用線程池可以控制資源,重復利用資源,穩(wěn)定服務器性能。
//創(chuàng)建一個固定線程數(shù)量的線程池,線程數(shù)量為10。
ExecutorService service = Executors.newFixedThreadPool(10);
//提交線程的兩種方式:
//1.submit(),返回 Future<T>,可以獲取返回結(jié)果
Future<Integer> submit = service.submit(new TestThread3());
//2.execute(),無返回值。
service.execute(new TestThread2());
}
}
當前線程:pool-1-thread-1
運行結(jié)果:5
線程池七大參數(shù):
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
/**
* @param corePoolSize
* 核心線程數(shù)【一直存在,除非設置allowCoreThreadTimeOut】,線程池
* 創(chuàng)建好以后就準備就緒的線程數(shù)量,等待執(zhí)行任務
* @param maximumPoolSize
* 線程池允許的最大的線程數(shù)量,可以控制資源
* @param keepAliveTime
* 存活時間,如果當前線程數(shù)量大于核心數(shù)量時,空閑線程釋放時間
* @param
* keepAliveTime 的時間單位。
* @param workQueue
* 阻塞隊列。如果任務有很多, 就會將目前多的任務放在隊列里面。
* 只要有線程空閑,就會去隊列里面取出新的任務繼續(xù) 執(zhí)行。
* @param threadFactory
* 線程的創(chuàng)建工廠,可以自定義線程名稱。
* @param handler
* 拒絕策略,如果阻塞隊列滿了,按照我們指定的拒絕策略拒絕執(zhí)行任務。
拒絕策略:
RejectedExecutionHandler提供了四種方式來處理任務拒絕策略:
DiscardOldestPolicy:丟棄隊列中最老的任務
AbortPolicy:拋異常(默認)
CallerRunsPolicy:將任務分給調(diào)用線程來執(zhí)行
DiscardPolicy:直接丟棄
工作順序 :
1、線程池創(chuàng)建,準備好core數(shù)量的核心線程,準備接受任務
2、任務進來,用core中空閑的線程執(zhí)行。
? ?? ? 1)、core線程沒有空閑的,就將再進來的任務放入阻塞隊列中。當core線程空閑就去阻塞隊列獲取任務執(zhí)行。
? ? ? ? 2)、阻塞隊列滿了,就直接開新的線程執(zhí)行,最大只能開到max指定的數(shù)量。
? ? ? ? 3)、所有任務執(zhí)行完畢,大于core線程數(shù)量的空閑線程,會在keepAliveTime指定的時間后,自動銷毀,最終保持到core大小的線程數(shù)量。
4)、如果線程數(shù)已經(jīng)達到max的數(shù)量 ,還有新任務進來,就會使用指定的拒絕策略進行處理。
3、所有的線程創(chuàng)建都是由指定的factory創(chuàng)建。