系列文章目錄
第一章 Java線程池技術(shù)應(yīng)用
前言
介紹Java的線程、線程池等操作
1、Java創(chuàng)建線程方式回顧
1.1、繼承Thread類(只運行一次)
public class ThreadTest extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
new ThreadTest().start();
}
}
1.1.1、改造成主線程常駐,每秒開啟新線程運行
import java.util.Date;
@Slf4j
public class ThreadTest extends Thread{
@Override
public void run() {
log.info("線程名稱:{} , 當(dāng)前時間:{}" , Thread.currentThread().getName() , new Date().getTime() );
}
public static void main(String[] args) {
while (true) {
try {
new ThreadTest().start();
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("主線程常駐");
}
}
}
1.1.2、匿名內(nèi)部類
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ThreadTest extends Thread{
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
log.info("Hello {}" , "world");
}
};
thread.start();
}
}
1.1.3、缺點
繼承了Thread類之后,就不能繼承其他類
1.1.4、擴展知識:Java內(nèi)部類
成員內(nèi)部類(外部類內(nèi)部使用,外部類外部使用)
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Outer {
public static void main(String[] args) {
Inner inner = new Outer().initTest();
log.info(inner.innerTest());
}
public Inner initTest(){
Inner inner = new Inner();
return inner;
}
class Inner{
public Inner(){
}
public Inner(String s){
}
public String innerTest(){
return "Inner Hello world";
}
}
}
1.1.4.1、靜態(tài)內(nèi)部類
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Outer {
public static void main(String[] args) {
Inner inner = new Inner();
log.info(inner.innerTest());
}
public void initTest(){
Inner inner = new Inner();
}
static class Inner{
public Inner(){
}
public Inner(String s){
}
public String innerTest(){
return "Inner Hello world";
}
}
}
1.1.4.2、匿名內(nèi)部類
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Outer {
public static void main(String[] args) {
Outer outer = new Outer();
outer.sayHello();
}
public void sayHello(){
IMessage iMessage = new IMessage() {
//匿名類
@Override
public String sayHello() {
return "Hello world";
}
};
log.info(iMessage.sayHello());
}
interface IMessage{
String sayHello();
}
}
1.2、實現(xiàn)Runnable接口
1.2.1、普通類實現(xiàn)Runnable接口
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class StatSales implements Runnable{
@Override
public void run() {
log.info("統(tǒng)計銷量");
}
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
log.info("Hello world");
}
};
thread.start();
}
}
1.2.2、匿名方式創(chuàng)建Runnable實現(xiàn)類
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("統(tǒng)計成績");
}
};
new Thread(runnable).start();
}
1.2.3、使用Lambda方式創(chuàng)建匿名Runnable類
// 使用 Lambda 匿名 Runnable 方式
Thread t3 = new Thread(() -> {
//添加業(yè)務(wù)方法…
});
// 啟動線程
t3.start();
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("統(tǒng)計平均壽命");
});
thread.start();
}
1.2.4、缺點
不能獲得程序的執(zhí)行結(jié)果
1.2.5、擴展Lambda表達式
把函數(shù)作為一個方法的參數(shù)
表達式語法:
(parameters) -> expression
或
(parameters) ->{ statements; }
說明:
- 可選類型聲明:不需要聲明參數(shù)類型,編譯器可以統(tǒng)一識別參數(shù)值。
- 可選的參數(shù)圓括號:一個參數(shù)無需定義圓括號,但多個參數(shù)需要定義圓括號。
- 可選的大括號:如果主體包含了一個語句,就不需要使用大括號。
- 可選的返回關(guān)鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指定表達式返回了一個數(shù)值。
-
舉例:
// 1. 不需要參數(shù),返回值為 5 () -> 5 // 2. 接收一個參數(shù)(數(shù)字類型),返回其2倍的值 x -> 2 * x // 3. 接受2個參數(shù)(數(shù)字),并返回他們的差值 (x, y) -> x – y // 4. 接收2個int型整數(shù),返回他們的和 (int x, int y) -> x + y // 5. 接受一個 string 對象,并在控制臺打印,不返回任何值(看起來像是返回void) (String s) -> System.out.print(s)
1.3、實現(xiàn)Callable接口
FutureTask+Callable
1.3.1、普通類實現(xiàn)Callable接口
public class StatScore implements Callable<Double> { @Override public Double call() throws Exception { //統(tǒng)計分?jǐn)?shù)的邏輯 return 88.98; } }
public static void main(String[] args) throws ExecutionException, InterruptedException { StatScore statScore = new StatScore(); //跟FutureTask 關(guān)聯(lián)上 FutureTask<Double> doubleFutureTask = new FutureTask<>(statScore); //跟Thread關(guān)聯(lián)上 Thread thread = new Thread(doubleFutureTask); thread.start(); log.info(String.valueOf(doubleFutureTask.get())); }
2、線程池
線程池就是存放線程的池子,池子里存放了很多可以復(fù)用的線程。
使用線程池的優(yōu)勢 - 提高效率,創(chuàng)建好一定數(shù)量的線程放在池中,等需要使用的時候就從池中拿一個,這要比需要的時候創(chuàng)建一個線程對象要快的多。
- 減少了創(chuàng)建和銷毀線程的次數(shù),每個工作線程都可以被重復(fù)利用,可執(zhí)行多個任務(wù)。
- 提升系統(tǒng)響應(yīng)速度,假如創(chuàng)建線程用的時間為T1,執(zhí)行任務(wù)用的時間為T2,銷毀線程用的時間為T3,那么使用線程池就免去了T1和T3的時間;
-
2.1、五種創(chuàng)建線程的方式
//創(chuàng)建一個單線程池,它只會用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級)執(zhí)行
ExecutorService executorService = Executors.newSingleThreadExecutor();
//創(chuàng)建一個定長的線程池,可控制最大并發(fā)數(shù),超出的線程進行隊列等待。 ExecutorService executorService =
Executors.newFixedThreadPool(2); //可以創(chuàng)建定長的、支持定時任務(wù),周期任務(wù)執(zhí)行。
ExecutorService executorService = Executors.newScheduledThreadPool(2);
//創(chuàng)建一個可以緩存的線程池,如果線程池長度超過處理需要,可以靈活回收空閑線程,沒回收的話就新建線程 ExecutorService
executorService = Executors.newCachedThreadPool(); //創(chuàng)建一個具有搶占式操作的線程池
ExecutorService executorService = Executors.newWorkStealingPool();2.2、new ThreadPoolExecutor()創(chuàng)建線程
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
參數(shù)說明:
參數(shù) 含義 解釋 corePoolSize 該線程池中核心線程數(shù)最大值 核心線程生命周期無限,即使空閑也不會死亡 maximumPoolSize 線程總數(shù)最大值 任務(wù)隊列滿了以后當(dāng)有新任務(wù)進來則會增加一個線程來處理新任務(wù)(線程總數(shù)<maximumPoolSize ) keepAliveTime 閑置超時時間 當(dāng)線程數(shù)大于核心線程數(shù)時,超過keepAliveTime時間將會回收非核心線程 unit keepAliveTime 的單位 workQueue 線程池中的任務(wù)隊列 * threadFactory 為線程池提供創(chuàng)建新線程的線程工廠 * RejectedExecutionHandler 飽和策略 拋出異常專用,當(dāng)隊列和最大線程池都滿了之后的飽和策略。 2.2.1、拒絕策略
ThreadPoolExecutor的飽和策略可以通過調(diào)用setRejectedExecutionHandler來修改。JDK提供了幾種不同的RejectedExecutionHandler實現(xiàn),每種實現(xiàn)都包含有不同的飽和策略:AbortPolicy、CallerRunsPolicy、DiscardPolicy和DiscardOldestPolicy。
拒絕策略如下:文章來源:http://www.zghlxwxcb.cn/news/detail-721371.html
- CallerRunsPolicy : 調(diào)用線程處理任務(wù)
- AbortPolicy : 拋出異常
- DiscardPolicy : 直接丟棄
- DiscardOldestPolicy : 丟棄隊列中最老的任務(wù),執(zhí)行新任務(wù)
-
RejectedExecutionHandler rejected = null; //默認(rèn)策略,阻塞隊列滿,則丟任務(wù)、拋出異常 rejected = new ThreadPoolExecutor.AbortPolicy(); //阻塞隊列滿,則丟任務(wù),不拋異常 rejected = new ThreadPoolExecutor.DiscardPolicy(); //刪除隊列中最舊的任務(wù)(最早進入隊列的任務(wù)),嘗試重新提交新的任務(wù) rejected = new ThreadPoolExecutor.DiscardOldestPolicy(); //隊列滿,不丟任務(wù),不拋異常,若添加到線程池失敗,那么主線程會自己去執(zhí)行該任務(wù) rejected = new ThreadPoolExecutor.CallerRunsPolicy();
總結(jié): 就是被拒絕的任務(wù),直接在主線程中運行,不再進入線程池。文章來源地址http://www.zghlxwxcb.cn/news/detail-721371.html
到了這里,關(guān)于微服務(wù) 第一章 Java線程池技術(shù)應(yīng)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!