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.mzph.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;判断约束的资源字段是…