1. 程式人生 > 其它 >【Leetcode每日筆記】714.買賣股票的最佳時機(Python)

【Leetcode每日筆記】714.買賣股票的最佳時機(Python)

技術標籤:springboot

一 介紹

工作中經常涉及非同步任務,通常是使用多執行緒技術,比如執行緒池ThreadPoolExecutor,但使用Executors容易產生OOM,需要手動使用ThreadPoolExecutor建立執行緒池;在springboot使用 @async 可以實現非同步呼叫,配置執行緒池引數,可以簡單的實現多執行緒的執行緒池效果,從而簡化開發,避免OOM;

二 非同步呼叫

2.1無返回非同步

我們知道同步執行就是按照程式碼的順序執行,而非同步執行則是無序,在springboot中使用實現非同步呼叫函式非常簡單,首先在啟動類上加上@EnableAsync 註解;

/**
 * @Author lsc
 * <p> </p>
 */
@SpringBootApplication
@EnableAsync
public class AsyncRunApp {

    public static void main(String[] args) {
        SpringApplication.run(AsyncRunApp.class, args);
    }
}

其次,在函式上標上@sync註解,表示非同步呼叫

    @Async
    public void taskOne() throws Exception {
        System.
out.println("任務一"); } @Async public void taskTwo() throws Exception { System.out.println("任務二"); }

測試程式碼

    @Autowired
    Task task;

    @Test
    public void test() throws Exception {
        task.taskOne();
        task.taskTwo();
    }

如果按照同步執行邏輯會先執行任務一,然後再執行任務二,如果是非同步執行,則無序,可能任務一先執行,也可能任務二先執行;

2.2 有返回值回撥

有時候要知道任務是否執行完成,再繼續做其它的業務邏輯,就需要使用到Future介面,其含義是在執行非同步任務後會給一個回撥函式,我們只要設定回撥資訊,就可以知道任務是否正確執行完成;我們對非同步函式,新增 Future 返回值型別,使用 new AsyncResult<>() 設定回撥資訊;

@Component
public class Task {

    @Async
    public Future<String> taskOne() throws Exception {
        System.out.println("任務一");
        return new AsyncResult<>("任務一執行完成");

    }

    @Async
    public Future<String> taskTwo() throws Exception {
        System.out.println("任務二");
        return new AsyncResult<>("任務二執行完成");
    }
}

測試程式碼如下, 等待2個任務全部完成後就打印出返回值資訊

 @Autowired
    Task task;

    @Test
    public void test() throws Exception {
        Future<String> str1 = task.taskOne();
        Future<String> str2 = task.taskTwo();
        while (true){
            // 如果任務都做完就執行如下邏輯
            if (str1.isDone() && str2.isDone()){
                System.out.println(str1.get()+":"+str2.get());
                break;
            }
        }
    }

執行輸出

任務二
任務一
任務一執行完成:任務二執行完成

關注公眾號 知識追尋者 獲取原創PDF,面試題集,最新成熟技術棧

三 執行緒池

在非同步掉用中使用的@Async 註解,預設的執行緒池大小如下;

# 核心執行緒數
spring.task.execution.pool.core-size=8  
# 最大執行緒數
spring.task.execution.pool.max-size=16
# 空閒執行緒存活時間
spring.task.execution.pool.keep-alive=60s
# 是否允許核心執行緒超時
spring.task.execution.pool.allow-core-thread-timeout=true
# 執行緒佇列數量
spring.task.execution.pool.queue-capacity=100
# 執行緒關閉等待
spring.task.execution.shutdown.await-termination=false
spring.task.execution.shutdown.await-termination-period=
# 執行緒名稱字首
spring.task.execution.thread-name-prefix=task-

一般情況下,我們都需要手動建立執行緒池,使用 ThreadPoolTaskExecutor 類進行配置;這邊設定了執行緒字首名稱,等下測試時就可以判定是否執行緒池配置成功;

@Configuration
public class PoolConfig {

    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 設定核心執行緒數
        executor.setCorePoolSize(10);
        // 設定最大執行緒數
        executor.setMaxPoolSize(15);
        // 設定佇列容量
        executor.setQueueCapacity(20);
        // 設定執行緒活躍時間(秒)
        executor.setKeepAliveSeconds(60);
        // 設定預設執行緒名稱
        executor.setThreadNamePrefix("zszxz-");
        // 設定拒絕策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任務結束後再關閉執行緒池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}

在task類中加上 新的一個方法如下

    @Async
    public void sayHello(String name) {
        LoggerFactory.getLogger(Task.class).info(name + ":Hello World!");
    }

使用測試類進行測試

   @Test
    public void testPool() throws Exception {
        task.sayHello("公眾號:知識追尋者");
    }

執行結果如下,日誌打印出執行緒名稱為zszxz-1;

有時候,一個專案中如果配置了多個執行緒池,如下格式

	@Bean("pool1")
    public TaskExecutor taskExecutor1() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //....
        return executor;
    }
    @Bean("pool2")
    public TaskExecutor taskExecutor2() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //....
        return executor;
    }
    @Bean("pool3")
    public TaskExecutor taskExecutor3() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //....
        return executor;
    }

在使用 @Async註解時就需要指明具體使用的執行緒池,如下格式

    @Async("pool1")
    public void sayHello1(String name) {
        LoggerFactory.getLogger(Task.class).info(name + ":Hello World!");
    }
    
     @Async("pool2")
    public void sayHello1(String name) {
        LoggerFactory.getLogger(Task.class).info(name + ":Hello World!");
    }

原始碼地址:https://github.com/zszxz/study-springboot