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,一经查实,立即删除!

相关文章

通过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…

实验五报告

一、实验结论&#xff1a; 1. 二分查找&#xff1a;补足程序ex1_1.cpp// 练习&#xff1a;使用二分查找&#xff0c;在一组有序元素中查找数据项 // 形参是数组&#xff0c;实参是数组名 #include <stdio.h> const int N5; int binarySearch(int x[], int n, int item…

实验五 网络编程与安全-----实验报告

一、实验五 网络编程与安全-1 1.实验要求&#xff1a; 两人一组结对编程&#xff1a; &#xff08;1&#xff09;参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA &#xff1b; &#xff08;2&#xff09;结对实现中缀表达式转后缀表达式的功能 MyBC.java&#xff1b…

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 …

phpstudy如何安装景安ssl证书 window下apache服务器网站https访问

1. 下载景安免费证书 https://www.zzidc.com/help/helpDetail?id555 2.文件解压上传至服务器&#xff0c;位置自己决定 3. 调整apache配置 景安原文链接&#xff1a;https://www.zzidc.com/help/helpDetail?id555 ① 确保你的apache编译了ssl模块&#xff0c;这是支持ssl证书…

docker下gitlab安装配置使用(完整版)

docker下gitlab安装配置使用(完整版) 22018.12.16 00:07:57字数 737阅读 17595 docker 安装gitlab以及使用 一、安装及配置 1.gitlab镜像拉取 # gitlab-ce为稳定版本&#xff0c;后面不填写版本则默认pull最新latest版本 $ docker pull gitlab/gitlab-ce拉取镜像 2.运行g…

企业级应用,如何实现服务化一(项目架构演化)

1.企业级应用架构演化 1.1.架构演化图 1.2.文字描述 #单一应用架构当网站流量很小时&#xff0c;只需一个应用&#xff0c;将所有功能都部署在一起&#xff0c;以减少部署节点和成本#垂直应用架构当访问量逐渐增大&#xff0c;单一应用增加机器带来的加速度越来越小&#xff0c…

readonly的用法

转载于:https://www.cnblogs.com/w123w/p/10958567.html

Jenkins发布spring boot到hub.Docker 方法

在生成的目录下&#xff0c;建立个文件&#xff0c;文件名称为&#xff1a;Dockerfile FROM java:8 VOLUME /tmp ADD target/assignment-0.0.1-SNAPSHOT.jar /dalaoyang.jar ENTRYPOINT ["java","-Djava.security.egdfile:/dev/./urandom","-jar&q…

网页视频直播、微信视频直播技术解决方案:EasyNVR与EasyDSS流媒体服务器组合之区分不同场景下的直播接入需求...

背景分析 熟悉EasyNVR产品的朋友们都知道&#xff0c;EasyNVR不仅可以独成体系&#xff0c;而且还可以跟其他系列产品相配合&#xff0c;形成各种不同类型的解决方案&#xff0c;满足各种不同应用场景的实际需求。针对很多设备现场没有固定公网IP&#xff0c;但是又想实现公网、…

如何解决VMware Workstation 10.0.0 build-1295980马赛克现象

VMware Workstation 10.0.0 build-1295980偶尔出现客户机马赛克现象&#xff0c;可切换至其它选项卡&#xff0c;再切换回去即可。 还有一种方式是关闭加速3D图形。 转载于:https://www.cnblogs.com/rms365/p/10961499.html

不同账号间的云资源授权方法

阿里云的访问控制RAM产品可以实现资源的分配和授权,在一个特殊的业务背景下,资源也可以实现跨账号的授权使用. 背景: 1.A公司,作为甲方Party A,出资购买云资源,对云资源具有所有权,但不实际管理,需要乙方配合. 2.B公司,作为乙方Party B,要管理A公司的云资源,需要A公司授权云资…

知乎上已获千赞,持续更新中

前言 不知不觉自己已经做了几年开发了&#xff0c;由记得刚出来工作的时候感觉自己能牛逼&#xff0c;现在回想起来感觉好无知。懂的越多的时候你才会发现懂的越少。 如果你的知识是一个圆&#xff0c;当你的圆越大时&#xff0c;圆外面的世界也就越大。 最近看到很多Androi…

centos下搭建Jenkins持续集成环境(安装jenkins)

centos下搭建Jenkins持续集成环境(安装jenkins) 1、安装JDK yum install -y java 2、安装jenkins 添加Jenkins库到yum库&#xff0c;Jenkins将从这里下载安装。 1 wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo 2 rpm --import h…

离开小厂进大厂的第一周,BTAJ大厂最新面试题汇集,面试总结

大佬带你走进Android开发的世界&#xff0c;掌握了这些知识点&#xff0c;学习Android也可以很轻松。 核心分析内容 对于怎么学习Android&#xff0c;主要解决的是3个问题&#xff1a;学什么、怎么学 & 怎么用。 具体如下&#xff1a; 下面&#xff0c;我将带着上述几个问…

程序员35岁真的是分水岭吗?小白也能看明白

前言 今天我给大家再次分享一下&#xff0c;我最近的一些读书的感想&#xff0c;思考起来&#xff0c;确实能够给自己带来一些真实的帮助和启发&#xff0c;希望大家在平时的工作学习中&#xff0c;也能够认清楚学习的一些本质。 如果我们的学习是在不断掌握应对具体工作场景…