springboot線程池的使用和擴展

實戰環境

  1. windowns10;
  2. jdk1.8;
  3. springboot 1.5.9.RELEASE;
  4. 開發工具:IntelliJ IDEA;

實戰源碼

本次實戰的源碼可以在我的GitHub下載,地址:git@github.com:zq2599/blog_demos.git,項目主頁:https://github.com/zq2599/blog_demos

這里面有多個工程,本次用到的工程為threadpooldemoserver,如下圖紅框所示:?
這里寫圖片描述

實戰步驟梳理

本次實戰的步驟如下:?
1. 創建springboot工程;?
2. 創建Service層的接口和實現;?
3. 創建controller,開發一個http服務接口,里面會調用service層的服務;?
4. 創建線程池的配置;?
5. 將Service層的服務異步化,這樣每次調用都會都被提交到線程池異步執行;?
6. 擴展ThreadPoolTaskExecutor,在提交任務到線程池的時候可以觀察到當前線程池的情況;

創建springboot工程

用IntelliJ IDEA創建一個springboot的web工程threadpooldemoserver,pom.xml內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.bolingcavalry</groupId><artifactId>threadpooldemoserver</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>threadpooldemoserver</name><description>Demo project for Spring Boot</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.9.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

創建Service層的接口和實現

創建一個service層的接口AsyncService,如下:

public interface AsyncService {/*** 執行異步任務*/void executeAsync();
}

對應的AsyncServiceImpl,實現如下:

@Service
public class AsyncServiceImpl implements AsyncService {private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class);@Overridepublic void executeAsync() {logger.info("start executeAsync");try{Thread.sleep(1000);}catch(Exception e){e.printStackTrace();}logger.info("end executeAsync");}
}

這個方法做的事情很簡單:sleep了一秒鐘;

創建controller

創建一個controller為Hello,里面定義一個http接口,做的事情是調用Service層的服務,如下:

@RestController
public class Hello {private static final Logger logger = LoggerFactory.getLogger(Hello.class);@Autowiredprivate AsyncService asyncService;@RequestMapping("/")public String submit(){logger.info("start submit");//調用service層的任務asyncService.executeAsync();logger.info("end submit");return "success";}
}

至此,我們已經做好了一個http請求的服務,里面做的事情其實是同步的,接下來我們就開始配置springboot的線程池服務,將service層做的事情都提交到線程池中去處理;

springboot的線程池配置

創建一個配置類ExecutorConfig,用來定義如何創建一個ThreadPoolTaskExecutor,要使用@Configuration和@EnableAsync這兩個注解,表示這是個配置類,并且是線程池的配置類,如下所示:

@Configuration
@EnableAsync
public class ExecutorConfig {private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);@Beanpublic Executor asyncServiceExecutor() {logger.info("start asyncServiceExecutor");ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//配置核心線程數executor.setCorePoolSize(5);//配置最大線程數executor.setMaxPoolSize(5);//配置隊列大小executor.setQueueCapacity(99999);//配置線程池中的線程的名稱前綴executor.setThreadNamePrefix("async-service-");// rejection-policy:當pool已經達到max size的時候,如何處理新任務// CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//執行初始化executor.initialize();return executor;}
}

注意,上面的方法名稱為asyncServiceExecutor,稍后馬上用到;

將Service層的服務異步化

打開AsyncServiceImpl.java,在executeAsync方法上增加注解@Async(“asyncServiceExecutor”),asyncServiceExecutor是前面ExecutorConfig.java中的方法名,表明executeAsync方法進入的線程池是asyncServiceExecutor方法創建的,如下:

@Override@Async("asyncServiceExecutor")public void executeAsync() {logger.info("start executeAsync");try{Thread.sleep(1000);}catch(Exception e){e.printStackTrace();}logger.info("end executeAsync");}

驗證效果

  1. 將這個springboot運行起來(pom.xml所在文件夾下執行mvn spring-boot:run);
  2. 在瀏覽器輸入:http://localhost:8080;
  3. 在瀏覽器用F5按鈕快速多刷新幾次;
  4. 在springboot的控制臺看見日志如下:
2018-01-21 22:43:18.630  INFO 14824 --- [nio-8080-exec-8] c.b.t.controller.Hello                   : start submit
2018-01-21 22:43:18.630  INFO 14824 --- [nio-8080-exec-8] c.b.t.controller.Hello                   : end submit
2018-01-21 22:43:18.929  INFO 14824 --- [async-service-1] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:18.930  INFO 14824 --- [async-service-1] c.b.t.service.impl.AsyncServiceImpl      : start executeAsync
2018-01-21 22:43:19.005  INFO 14824 --- [async-service-2] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:19.006  INFO 14824 --- [async-service-2] c.b.t.service.impl.AsyncServiceImpl      : start executeAsync
2018-01-21 22:43:19.175  INFO 14824 --- [async-service-3] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:19.175  INFO 14824 --- [async-service-3] c.b.t.service.impl.AsyncServiceImpl      : start executeAsync
2018-01-21 22:43:19.326  INFO 14824 --- [async-service-4] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:19.495  INFO 14824 --- [async-service-5] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:19.930  INFO 14824 --- [async-service-1] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:20.006  INFO 14824 --- [async-service-2] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:20.191  INFO 14824 --- [async-service-3] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync

?

如上日志所示,我們可以看到controller的執行線程是”nio-8080-exec-8”,這是tomcat的執行線程,而service層的日志顯示線程名為“async-service-1”,顯然已經在我們配置的線程池中執行了,并且每次請求中,controller的起始和結束日志都是連續打印的,表明每次請求都快速響應了,而耗時的操作都留給線程池中的線程去異步執行;

擴展ThreadPoolTaskExecutor

雖然我們已經用上了線程池,但是還不清楚線程池當時的情況,有多少線程在執行,多少在隊列中等待呢?這里我創建了一個ThreadPoolTaskExecutor的子類,在每次提交線程的時候都會將當前線程池的運行狀況打印出來,代碼如下:

public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {private static final Logger logger = LoggerFactory.getLogger(VisiableThreadPoolTaskExecutor.class);private void showThreadPoolInfo(String prefix){ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();if(null==threadPoolExecutor){return;}logger.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",this.getThreadNamePrefix(),prefix,threadPoolExecutor.getTaskCount(),threadPoolExecutor.getCompletedTaskCount(),threadPoolExecutor.getActiveCount(),threadPoolExecutor.getQueue().size());}@Overridepublic void execute(Runnable task) {showThreadPoolInfo("1. do execute");super.execute(task);}@Overridepublic void execute(Runnable task, long startTimeout) {showThreadPoolInfo("2. do execute");super.execute(task, startTimeout);}@Overridepublic Future<?> submit(Runnable task) {showThreadPoolInfo("1. do submit");return super.submit(task);}@Overridepublic <T> Future<T> submit(Callable<T> task) {showThreadPoolInfo("2. do submit");return super.submit(task);}@Overridepublic ListenableFuture<?> submitListenable(Runnable task) {showThreadPoolInfo("1. do submitListenable");return super.submitListenable(task);}@Overridepublic <T> ListenableFuture<T> submitListenable(Callable<T> task) {showThreadPoolInfo("2. do submitListenable");return super.submitListenable(task);}
}

如上所示,showThreadPoolInfo方法中將任務總數、已完成數、活躍線程數,隊列大小都打印出來了,然后Override了父類的execute、submit等方法,在里面調用showThreadPoolInfo方法,這樣每次有任務被提交到線程池的時候,都會將當前線程池的基本情況打印到日志中;

修改ExecutorConfig.java的asyncServiceExecutor方法,將ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor()改為ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor(),如下所示:

@Beanpublic Executor asyncServiceExecutor() {logger.info("start asyncServiceExecutor");//使用VisiableThreadPoolTaskExecutorThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();//配置核心線程數executor.setCorePoolSize(5);//配置最大線程數executor.setMaxPoolSize(5);//配置隊列大小executor.setQueueCapacity(99999);//配置線程池中的線程的名稱前綴executor.setThreadNamePrefix("async-service-");// rejection-policy:當pool已經達到max size的時候,如何處理新任務// CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//執行初始化executor.initialize();return executor;}
  • 1

再次啟動該工程,再瀏覽器反復刷新http://localhost:8080,看到的日志如下:

2018-01-21 23:04:56.113  INFO 15580 --- [nio-8080-exec-1] c.b.t.e.VisiableThreadPoolTaskExecutor   : async-service-, 2. do submit,taskCount [99], completedTaskCount [85], activeCount [5], queueSize [9]
2018-01-21 23:04:56.113  INFO 15580 --- [nio-8080-exec-1] c.b.t.controller.Hello                   : end submit
2018-01-21 23:04:56.225  INFO 15580 --- [async-service-1] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 23:04:56.225  INFO 15580 --- [async-service-1] c.b.t.service.impl.AsyncServiceImpl      : start executeAsync
2018-01-21 23:04:56.240  INFO 15580 --- [nio-8080-exec-2] c.b.t.controller.Hello                   : start submit
2018-01-21 23:04:56.240  INFO 15580 --- [nio-8080-exec-2] c.b.t.e.VisiableThreadPoolTaskExecutor   : async-service-, 2. do submit,taskCount [100], completedTaskCount [86], activeCount [5], queueSize [9]
2018-01-21 23:04:56.240  INFO 15580 --- [nio-8080-exec-2] c.b.t.controller.Hello                   : end submit
2018-01-21 23:04:56.298  INFO 15580 --- [async-service-2] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 23:04:56.298  INFO 15580 --- [async-service-2] c.b.t.service.impl.AsyncServiceImpl      : start executeAsync
2018-01-21 23:04:56.372  INFO 15580 --- [nio-8080-exec-3] c.b.t.controller.Hello                   : start submit
2018-01-21 23:04:56.373  INFO 15580 --- [nio-8080-exec-3] c.b.t.e.VisiableThreadPoolTaskExecutor   : async-service-, 2. do submit,taskCount [101], completedTaskCount [87], activeCount [5], queueSize [9]
2018-01-21 23:04:56.373  INFO 15580 --- [nio-8080-exec-3] c.b.t.controller.Hello                   : end submit
2018-01-21 23:04:56.444  INFO 15580 --- [async-service-3] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 23:04:56.445  INFO 15580 --- [async-service-3] c.b.t.service.impl.AsyncServiceImpl      : start executeAsync

?

注意這一行日志:2. do submit,taskCount [101], completedTaskCount [87], activeCount [5], queueSize [9]

這說明提交任務到線程池的時候,調用的是submit(Callable task)這個方法,當前已經提交了101個任務,完成了87個,當前有5個線程在處理任務,還剩9個任務在隊列中等待,線程池的基本情況一路了然;

至此,springboot線程池服務的實戰就完成了,希望能幫您在工程中快速實現異步服務;

?

?

spring-boot 方法異步調用,自定義線程池配置使用

?

1、在主類中添加@EnableAsync注解:

@SpringBootApplication
@EnableScheduling
@EnableAsync
public class MySpringBootApplication {private static Logger logger = LoggerFactory.getLogger(MySpringBootApplication.class);public static void main(String[] args) {SpringApplication.run(MySpringBootApplication.class, args);logger.info("My Spring Boot Application Started");}

2、創建一個AsyncTask類,在里面添加兩個用@Async注解的task:

@Component
public class AsyncTask {protected final Logger logger = LoggerFactory.getLogger(this.getClass());@Asyncpublic Future<String> doTask1() throws InterruptedException{logger.info("Task1 started.");long start = System.currentTimeMillis();Thread.sleep(5000);long end = System.currentTimeMillis();logger.info("Task1 finished, time elapsed: {} ms.", end-start);return new AsyncResult<>("Task1 accomplished!");}@Asyncpublic Future<String> doTask2() throws InterruptedException{logger.info("Task2 started.");long start = System.currentTimeMillis();Thread.sleep(3000);long end = System.currentTimeMillis();logger.info("Task2 finished, time elapsed: {} ms.", end-start);return new AsyncResult<>("Task2 accomplished!");}
}

3、萬事俱備,開始測試:


public class TaskTests extends BasicUtClass{@Autowiredprivate AsyncTask asyncTask;@Testpublic void AsyncTaskTest() throws InterruptedException, ExecutionException {Future<String> task1 = asyncTask.doTask1();Future<String> task2 = asyncTask.doTask2();while(true) {if(task1.isDone() && task2.isDone()) {logger.info("Task1 result: {}", task1.get());logger.info("Task2 result: {}", task2.get());break;}Thread.sleep(1000);}logger.info("All tasks finished.");}
}

測試結果:

2016-12-13 11:12:24,850:INFO main (AsyncExecutionAspectSupport.java:245) - No TaskExecutor bean found for async processing
2016-12-13 11:12:24,864:INFO SimpleAsyncTaskExecutor-1 (AsyncTask.java:22) - Task1 started.
2016-12-13 11:12:24,865:INFO SimpleAsyncTaskExecutor-2 (AsyncTask.java:34) - Task2 started.
2016-12-13 11:12:27,869:INFO SimpleAsyncTaskExecutor-2 (AsyncTask.java:39) - Task2 finished, time elapsed: 3001 ms.
2016-12-13 11:12:29,866:INFO SimpleAsyncTaskExecutor-1 (AsyncTask.java:27) - Task1 finished, time elapsed: 5001 ms.
2016-12-13 11:12:30,853:INFO main (TaskTests.java:23) - Task1 result: Task1 accomplished!
2016-12-13 11:12:30,853:INFO main (TaskTests.java:24) - Task2 result: Task2 accomplished!
2016-12-13 11:12:30,854:INFO main (TaskTests.java:30) - All tasks finished.

可以看到,沒有自定義的Executor,所以使用缺省的TaskExecutor 。

?

前面是最簡單的使用方法。如果想使用自定義的Executor,可以按照如下幾步來:

1、新建一個Executor配置類,順便把@EnableAsync注解搬到這里來:

@Configuration
@EnableAsync
public class ExecutorConfig {/** Set the ThreadPoolExecutor's core pool size. */private int corePoolSize = 10;/** Set the ThreadPoolExecutor's maximum pool size. */private int maxPoolSize = 200;/** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */private int queueCapacity = 10;@Beanpublic Executor mySimpleAsync() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(corePoolSize);executor.setMaxPoolSize(maxPoolSize);executor.setQueueCapacity(queueCapacity);executor.setThreadNamePrefix("MySimpleExecutor-");executor.initialize();return executor;}@Beanpublic Executor myAsync() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(corePoolSize);executor.setMaxPoolSize(maxPoolSize);executor.setQueueCapacity(queueCapacity);executor.setThreadNamePrefix("MyExecutor-");// rejection-policy:當pool已經達到max size的時候,如何處理新任務// CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}
}

這里定義了兩個不同的Executor,第二個重新設置了pool已經達到max size時候的處理方法;同時指定了線程名字的前綴。

2、自定義Executor的使用:

@Component
public class AsyncTask {protected final Logger logger = LoggerFactory.getLogger(this.getClass());@Async("mySimpleAsync")public Future<String> doTask1() throws InterruptedException{logger.info("Task1 started.");long start = System.currentTimeMillis();Thread.sleep(5000);long end = System.currentTimeMillis();logger.info("Task1 finished, time elapsed: {} ms.", end-start);return new AsyncResult<>("Task1 accomplished!");}@Async("myAsync")public Future<String> doTask2() throws InterruptedException{logger.info("Task2 started.");long start = System.currentTimeMillis();Thread.sleep(3000);long end = System.currentTimeMillis();logger.info("Task2 finished, time elapsed: {} ms.", end-start);return new AsyncResult<>("Task2 accomplished!");}
}

就是把上面自定義Executor的類名,放進@Async注解中。

3、(測試用例不變)測試結果:

2016-12-13 10:57:11,998:INFO MySimpleExecutor-1 (AsyncTask.java:22) - Task1 started.
2016-12-13 10:57:12,001:INFO MyExecutor-1 (AsyncTask.java:34) - Task2 started.
2016-12-13 10:57:15,007:INFO MyExecutor-1 (AsyncTask.java:39) - Task2 finished, time elapsed: 3000 ms.
2016-12-13 10:57:16,999:INFO MySimpleExecutor-1 (AsyncTask.java:27) - Task1 finished, time elapsed: 5001 ms.
2016-12-13 10:57:17,994:INFO main (TaskTests.java:23) - Task1 result: Task1 accomplished!
2016-12-13 10:57:17,994:INFO main (TaskTests.java:24) - Task2 result: Task2 accomplished!
2016-12-13 10:57:17,994:INFO main (TaskTests.java:30) - All tasks finished.
2016-12-13 10:57:18,064 Thread-3 WARN Unable to register Log4j shutdown hook because JVM is shutting down. Using SimpleLogger

可見,線程名字的前綴變了,兩個task使用了不同的線程池了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/386754.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/386754.shtml
英文地址,請注明出處:http://en.pswp.cn/news/386754.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

統計單詞個數

我是抄題解狂魔 /* 1.s.substr(x,len) 在s中取出從x位置開始&#xff0c;長度為len的字符串&#xff0c;并返回string類型的字符串。 2.s.find(a) 在s中查找字符串a,并返回起始下標&#xff08;從0開始&#xff09;&#xff0c;若不存在&#xff0c;返回1844674407370955161&am…

通過Rancher安裝K8s

說明 我們用kubernetes去管理Docker集群&#xff0c;即可以將Docker看成Kubernetes內部使用的低級別組件。另外&#xff0c;kubernetes不僅僅支持Docker&#xff0c;還支持Rocket&#xff0c;這是另一種容器技術。希望我這篇文章中簡單的描述能讓你對兩者有所理解和認識。 機…

35. 搜索插入位置-LeetCode

心得&#xff1a;這個題也是二分查找&#xff0c;但是有個小技巧&#xff1a;當left>right的時候 left就是要插入的位置。 代碼&#xff1a; 1 class Solution {2 public int searchInsert(int[] nums, int target) {3 if(numsnull||nums.length0)4 …

Kubectl指令集

1 Kubectl指令集 1.1 Master查詢節點信息 [rootmaster1 kubernetes-1.10]# kubectl get nodes 1.2 查詢所有Pod信息 [rootmaster1 ~]# kubectl get pods --namespacekube-system 1.3 查詢故障的Pod信息 [rootmaster1 ~]# kubectl get pods -n kube-sys…

SQL基礎培訓實戰教程[全套]

學習簡介&#xff1a;林楓山根據網上搜索資料進行參考&#xff0c;編寫制作的SQL Server實操學習教程&#xff0c;歡迎下載學習。 下載鏈接目錄如下&#xff1a; 進度0-SQL基礎語法 下載學習文檔 進度1-建數據表-美化版-2018-6-12 下載學習文檔 進度2-關于主鍵-美化…

K8S儀表板Service unavailable故障的解決辦法

K8S儀表板Service unavailable故障的解決辦法 &#xff08;使用Rancher部署Kubernetes后訪問儀表板提示Service unavailable的問題&#xff09; 一、逐項檢查&#xff1a; 1、操作系統Kernel版本&#xff08;3.10以上&#xff09; 2、檢查OS版本&#xff08;Ubuntu16.04.x、…

實驗五報告

一、實驗結論&#xff1a; 1. 二分查找&#xff1a;補足程序ex1_1.cpp// 練習&#xff1a;使用二分查找&#xff0c;在一組有序元素中查找數據項 // 形參是數組&#xff0c;實參是數組名 #include <stdio.h> const int N5; int binarySearch(int x[], int n, int item…

關于瀏覽器內核

介紹一下對瀏覽器內核的理解主要分成兩個部分&#xff1a;渲染引擎(Render Engine)和JS引擎。常見的瀏覽器內核有哪些&#xff1f;Trident內核&#xff1a;IE&#xff0c;360&#xff0c;搜過瀏覽器&#xff1b;Gecko內核&#xff1a;Netscape6及以上版本&#xff0c;Presto內核…

docker 全部殺掉

殺死所有正在運行的容器 docker kill $(docker ps -a -q) 刪除所有已經停止的容器 docker rm $(docker ps -a -q) 刪除所有未打 dangling 標簽的鏡像 docker rmi $(docker images -q -f danglingtrue) 刪除所有鏡像 docker rmi $(docker images -q) 強制刪除鏡像名稱中包含“do…

實驗五 網絡編程與安全-----實驗報告

一、實驗五 網絡編程與安全-1 1.實驗要求&#xff1a; 兩人一組結對編程&#xff1a; &#xff08;1&#xff09;參考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA &#xff1b; &#xff08;2&#xff09;結對實現中綴表達式轉后綴表達式的功能 MyBC.java&#xff1b…

K8S的HelloWorld之旅

安裝kubectl。使用Google提供商&#xff08;如Google Container Engine或Amazon Web Services&#xff09;創建Kubernetes群集。本教程創建一個 外部負載均衡器&#xff0c;它需要一個云提供商。配置kubectl與Kubernetes API服務器通信。有關說明&#xff0c;請參閱云提供商的文…

思維構造——cf1090D

/* 只要找到兩個沒有關系的點即可 */ #include<bits/stdc.h> using namespace std; #define maxn 100005 long long n,m; int a[maxn],b[maxn]; vector<int>G[maxn]; int main(){cin>>n>>m;if(n1){puts("NO");return 0;}if(n*(n-1)/2<m)…

誤刪docker0網橋之后怎么辦呢?

誤刪docker0網橋之后怎么辦呢&#xff1f; 今天&#xff0c;在搭建k8s node節點環境的時候&#xff0c;好巧不巧&#xff0c;執行了如下命令&#xff1a; 1 2 [roothxin221 ~]# ifconfig docker0 down &>/dev/null [roothxin221 ~]# brctl delbr docker0 &>/de…

boost.asio學習

https://mmoaay.gitbooks.io/boost-asio-cpp-network-programming-chinese/content/Chapter1.html轉載于:https://www.cnblogs.com/hshy/p/10930398.html

Harbor:私有企業級Registry倉庫--快速搭建

前言 Harbor可以通過Docker Composer的方式來部署&#xff0c;如果有正常運行的k8s環境&#xff0c;也可以使用k8s來部署Harbor&#xff0c;本文采用 Docker Composer的方式。 準備 假定Linux系統為Centos 7。 docker &#xff0c;默認安裝即可 yum -y install docker 1 dock…

java-Mysql學生管理系統

Window1//主方法 package stu_zizhu1; import java.awt.Button; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JBu…

Docker版本Jenkins的使用

Docker版本Jenkins的使用 低調的微胖關注贊賞支持 Docker版本Jenkins的使用 12018.05.15 18:21:50字數 1202閱讀 22588 一. 什么是Jenkins Jenkins是當前非常流行的一款持續集成工具&#xff0c;可以幫助大家把更新后的代碼自動部署到服務器上運行。 二. 為什么用docker版…

小程序 setData 中的坑,其實好像...

最近這段時間在寫微信小程序&#xff0c;有一個頁面需要動態修改 data 中的數據&#xff0c;而這里似乎是個坑。 1、正常修改 正常修改很簡單&#xff0c;當觸發 change 事件時&#xff0c;數據和頁面都會同時發生改變。這個也不用多說&#xff0c;很簡單的例子。 2、如何修改對…

CentOS HarBor安裝與配置

HarBor 安裝與配置 Prerequisites for the target host ResourceCapacityDescriptionCPUminimal 2 CPU4 CPU is preferredMemminimal 4GB8GB is preferredDiskminimal 40GB160GB is preferred 環境 centos7harbor v1.6.3python v2.7及以上docker v1.10及以上docker-compose …

冪等

一種方案是創建唯一索引。在數據庫中針對我們需要約束的資源字段創建唯一索引&#xff0c;可以防止插入重復數據。但是&#xff0c;遇到分庫分表的場景&#xff0c;唯一索引也就不那么好使了&#xff0c; 此時&#xff0c;我們可以先查詢數據庫&#xff0c;判斷約束的資源字段是…