当前位置: 首页 > news >正文

怎么给餐饮店做网站做个购物网站

怎么给餐饮店做网站,做个购物网站,怎么做有趣的短视频网站,即时聊天wordpress手机app拿来即用!这篇文章我会介绍我使用线程池的时候应该注意的坑以及一些优秀的实践。 1、正确声明线程池 线程池必须手动通过 ThreadPoolExecutor 的构造函数来声明#xff0c;避免使用Executors 类创建线程池#xff0c;会有 OOM 风险。 Executors 返回线程池对象的弊端如下(…拿来即用!这篇文章我会介绍我使用线程池的时候应该注意的坑以及一些优秀的实践。 1、正确声明线程池 线程池必须手动通过 ThreadPoolExecutor 的构造函数来声明避免使用Executors 类创建线程池会有 OOM 风险。 Executors 返回线程池对象的弊端如下(后文会详细介绍到) FixedThreadPool 和 SingleThreadExecutor 使用的是无界的 LinkedBlockingQueue任务队列最大长度为 Integer.MAX_VALUE,可能堆积大量的请求从而导致 OOM。 CachedThreadPool 使用的是同步队列 SynchronousQueue, 允许创建的线程数量为 Integer.MAX_VALUE 可能会创建大量线程从而导致 OOM。 ScheduledThreadPool 和 SingleThreadScheduledExecutor : 使用的无界的延迟阻塞队列DelayedWorkQueue任务队列最大长度为 Integer.MAX_VALUE,可能堆积大量的请求从而导致 OOM。 说白了就是使用有界队列控制线程创建数量。 除了避免 OOM 的原因之外不推荐使用 Executors提供的两种快捷的线程池的原因还有 实际使用中需要根据自己机器的性能、业务场景来手动配置线程池的参数比如核心线程数、使用的任务队列、饱和策略等等。 我们应该显示地给我们的线程池命名这样有助于我们定位问题。 2、监测线程池运行状态 你可以通过一些手段来检测线程池的运行状态比如 SpringBoot 中的 Actuator 组件。 除此之外我们还可以利用 ThreadPoolExecutor 的相关 API 做一个简陋的监控。从下图可以看出 ThreadPoolExecutor提供了获取线程池当前的线程数和活跃线程数、已经执行完成的任务数、正在排队中的任务数等等。 图片 下面是一个简单的 Demo。printThreadPoolStatus()会每隔一秒打印出线程池的线程数、活跃线程数、完成的任务数、以及队列中的任务数。 /*** 打印线程池的状态** param threadPool 线程池对象*/ public static void printThreadPoolStatus(ThreadPoolExecutor threadPool) {ScheduledExecutorService scheduledExecutorService  new ScheduledThreadPoolExecutor(1, createThreadFactory(print-images/thread-pool-status, false));scheduledExecutorService.scheduleAtFixedRate(() - {log.info();log.info(ThreadPool Size: [{}], threadPool.getPoolSize());log.info(Active Threads: {}, threadPool.getActiveCount());log.info(Number of Tasks : {}, threadPool.getCompletedTaskCount());log.info(Number of Tasks in Queue: {}, threadPool.getQueue().size());log.info();}, 0, 1, TimeUnit.SECONDS); }3、建议不同类别的业务用不同的线程池 很多人在实际项目中都会有类似这样的问题我的项目中多个业务需要用到线程池是为每个线程池都定义一个还是说定义一个公共的线程池呢 一般建议是不同的业务使用不同的线程池配置线程池的时候根据当前业务的情况对当前线程池进行配置因为不同的业务的并发以及对资源的使用情况都不同重心优化系统性能瓶颈相关的业务。 我们再来看一个真实的事故案例 (本案例来源自《线程池运用不当的一次线上事故》 [1] 很精彩的一个案例) 案例代码概览 上面的代码可能会存在锁饥饿的情况你可以理解为是死锁的一种情况画个图给大家捋一捋。 假如我们线程池的核心线程数为 n 父任务扣费任务数量为 n 父任务下面有两个子任务扣费任务下的子任务其中一个已经执行完成另外一个被放在了任务队列中。由于父任务把线程池核心线程资源用完所以子任务因为无法获取到线程资源无法正常执行一直被阻塞在队列中。父任务等待子任务执行完成而子任务等待父任务释放线程池资源这也就造成了 锁饥饿 线程池使用不当导致死锁 解决方法也很简单就是新增加一个用于执行子任务的线程池专门为其服务。 4、别忘记给线程池命名 初始化线程池的时候需要显示命名设置线程池名称前缀有利于定位问题。 默认情况下创建的线程名字类似 pool-1-thread-n 这样的没有业务含义不利于我们定位问题。 给线程池里的线程命名通常有下面两种方式 1、利用 guava 的 ThreadFactoryBuilder ThreadFactory threadFactory  new ThreadFactoryBuilder().setNameFormat(threadNamePrefix  -%d).setDaemon(true).build(); ExecutorService threadPool  new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MINUTES, workQueue, threadFactory)2、自己实现 ThreadFactor。 import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; /*** 线程工厂它设置线程名称有利于我们定位问题。*/ public final class NamingThreadFactory implements ThreadFactory {private final AtomicInteger threadNum  new AtomicInteger();private final ThreadFactory delegate;private final String name;/*** 创建一个带名字的线程池生产工厂*/public NamingThreadFactory(ThreadFactory delegate, String name) {this.delegate  delegate;this.name  name; // TODO consider uniquifying this}Overridepublic Thread newThread(Runnable r) {Thread t  delegate.newThread(r);t.setName(name   [#  threadNum.incrementAndGet()  ]);return t;}}5、正确配置线程池参数 说到如何给线程池配置参数美团的骚操作至今让我难忘后面会提到 我们先来看一下各种书籍和博客上一般推荐的配置线程池参数的方式可以作为参考 常规操作 很多人甚至可能都会觉得把线程池配置过大一点比较好我觉得这明显是有问题的。线程数量过多的影响也是和我们分配多少人做事情一样对于多线程这个场景来说主要是增加了上下文切换 成本。不清楚什么是上下文切换的话可以看我下面的介绍。 上下文切换 多线程编程中一般线程的个数都大于 CPU 核心的个数而一个 CPU 核心在任意时刻只能被一个线程使用为了让这些线程都能得到有效执行CPU 采取的策略是为每个线程分配时间片并轮转的形式。当一个线程的时间片用完的时候就会重新处于就绪状态让给其他线程使用这个过程就属于一次上下文切换。概括来说就是当前任务在执行完 CPU 时间片切换到另一个任务之前会先保存自己的状态以便下次再切换回这个任务时可以再加载这个任务的状态。任务从保存到再加载的过程就是一次上下文切换 。 上下文切换通常是计算密集型的。也就是说它需要相当可观的处理器时间在每秒几十上百次的切换中每次切换都需要纳秒量级的时间。所以上下文切换对系统来说意味着消耗大量的 CPU 时间事实上可能是操作系统中时间消耗最大的操作。 Linux 相比与其他操作系统包括其他类 Unix 系统有很多的优点其中有一项就是其上下文切换和模式切换的时间消耗非常少。 如果我们设置的线程池数量太小的话如果同一时间有大量任务/请求需要处理可能会导致大量的请求/任务在任务队列中排队等待执行甚至会出现任务队列满了之后任务/请求无法处理的情况或者大量任务堆积在任务队列导致 OOM。这样很明显是有问题的CPU 根本没有得到充分利用。 如果我们设置线程数量太大大量线程可能会同时在争取 CPU 资源这样会导致大量的上下文切换从而增加线程的执行时间影响了整体执行效率。 有一个简单并且适用面比较广的公式 CPU 密集型任务(N1) 这种任务消耗的主要是 CPU 资源可以将线程数设置为 NCPU 核心数1。比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断或者其它原因导致的任务暂停而带来的影响。一旦任务暂停CPU 就会处于空闲状态而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。 I/O 密集型任务(2N) 这种任务应用起来系统会用大部分的时间来处理 I/O 交互而线程在处理 I/O 的时间段内不会占用 CPU 来处理这时就可以将 CPU 交出给其它线程使用。因此在 I/O 密集型任务的应用中我们可以多配置一些线程具体的计算方法是 2N。 如何判断是 CPU 密集任务还是 IO 密集任务 CPU 密集型简单理解就是利用 CPU 计算能力的任务比如你在内存中对大量数据进行排序。但凡涉及到网络读取文件读取这类都是 IO 密集型这类任务的特点是 CPU 计算耗费时间相比于等待 IO 操作完成的时间来说很少大部分时间都花在了等待 IO 操作完成上。 拓展一下 线程数更严谨的计算的方法应该是最佳线程数 NCPU 核心数∗1WT线程等待时间/ST线程计算时间其中 WT线程等待时间线程运行总时间 - ST线程计算时间。 线程等待时间所占比例越高需要越多线程。线程计算时间所占比例越高需要越少线程。 我们可以通过 JDK 自带的工具 VisualVM 来查看 WT/ST 比例。 CPU 密集型任务的 WT/ST 接近或者等于 0因此 线程数可以设置为 NCPU 核心数∗10 N和我们上面说的 NCPU 核心数1 差不多。 IO 密集型任务下几乎全是线程等待时间从理论上来说你就可以将线程数设置为 2N按道理来说WT/ST 的结果应该比较大这里选择 2N 的原因应该是为了避免创建过多线程吧。 后面介绍的美团的线程池参数动态配置这种方案就非常不错很实用 美团的骚操作 美团技术团队在《Java 线程池实现原理及其在美团业务中的实践》 [3]这篇文章中介绍到对线程池参数实现可自定义配置的思路和方法。 美团技术团队的思路是主要对线程池的核心参数实现自定义可配置。这三个核心参数是 corePoolSize : 核心线程数线程数定义了最小可以同时运行的线程数量。 maximumPoolSize : 当队列中存放的任务达到队列容量的时候当前可以同时运行的线程数量变为最大线程数。 workQueue: 当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数如果达到的话新任务就会被存放在队列中。 为什么是这三个参数 如何支持参数动态配置 且看 ThreadPoolExecutor 提供的下面这些方法。 图片 格外需要注意的是corePoolSize 程序运行期间的时候我们调用 setCorePoolSize这个方法的话线程池会首先判断当前工作线程数是否大于corePoolSize如果大于的话就会回收工作线程。 另外你也看到了上面并没有动态指定队列长度的方法美团的方式是自定义了一个叫做 ResizableCapacityLinkedBlockIngQueue 的队列主要就是把LinkedBlockingQueue的 capacity 字段的 final 关键字修饰给去掉了让它变为可变的。 最终实现的可动态修改线程池参数效果如下。 动态配置线程池参数最终效果 如果我们的项目也想要实现这种效果的话可以借助现成的开源项目 Hippo-4[4] 一款强大的动态线程池框架解决了传统线程池使用存在的一些痛点比如线程池参数没办法动态修改、不支持运行时变量的传递、无法执行优雅关闭。除了支持动态修改线程池参数、线程池任务传递上下文还支持通知报警、运行监控等开箱即用的功能。 Dynamic TP[5] 轻量级动态线程池内置监控告警功能集成三方中间件线程池管理基于主流配置中心已支持 Nacos、ApolloZookeeper、Consul、Etcd可通过 SPI 自定义实现。 6、线程池使用的一些小坑 重复创建线程池的坑 线程池是可以复用的一定不要频繁创建线程池比如一个用户请求到了就单独创建一个线程池。 GetMapping(wrong) public String wrong() throws InterruptedException {// 自定义线程池ThreadPoolExecutor executor  new ThreadPoolExecutor(5,10,1L,TimeUnit.SECONDS,new ArrayBlockingQueue(100),new ThreadPoolExecutor.CallerRunsPolicy());//  处理任务executor.execute(() - {// ......}return OK; }出现这种问题的原因还是对于线程池认识不够需要加强线程池的基础知识。 Spring 内部线程池的坑 使用 Spring 内部线程池时一定要手动自定义线程池配置合理的参数不然会出现生产问题一个请求创建一个线程。 Configuration EnableAsync public class ThreadPoolExecutorConfig {Bean(namethreadPoolExecutor)public Executor threadPoolExecutor(){ThreadPoolTaskExecutor threadPoolExecutor  new ThreadPoolTaskExecutor();int processNum  Runtime.getRuntime().availableProcessors(); // 返回可用处理器的Java虚拟机的数量int corePoolSize  (int) (processNum / (1 - 0.2));int maxPoolSize  (int) (processNum / (1 - 0.5));threadPoolExecutor.setCorePoolSize(corePoolSize); // 核心池大小threadPoolExecutor.setMaxPoolSize(maxPoolSize); // 最大线程数threadPoolExecutor.setQueueCapacity(maxPoolSize * 1000); // 队列程度threadPoolExecutor.setThreadPriority(Thread.MAX_PRIORITY);threadPoolExecutor.setDaemon(false);threadPoolExecutor.setKeepAliveSeconds(300);// 线程空闲时间threadPoolExecutor.setThreadNamePrefix(test-Executor-); // 线程名字前缀return threadPoolExecutor;} }线程池和 ThreadLocal 共用的坑 线程池和 ThreadLocal共用可能会导致线程从ThreadLocal获取到的是旧值/脏数据。 这是因为线程池会复用线程对象与线程对象绑定的类的静态属性 ThreadLocal 变量也会被重用这就导致一个线程可能获取到其他线程的ThreadLocal 值。 不要以为代码中没有显示使用线程池就不存在线程池了像常用的 Web 服务器 Tomcat 处理任务为了提高并发量就使用到了线程池并且使用的是基于原生 Java 线程池改进完善得到的自定义线程池。 当然了你可以将 Tomcat 设置为单线程处理任务。不过这并不合适会严重影响其处理任务的速度。 server.tomcat.max-threads1解决上述问题比较建议的办法是使用阿里巴巴开源的 TransmittableThreadLocal(TTL)。 TransmittableThreadLocal类继承并加强了 JDK 内置的InheritableThreadLocal类在使用线程池等会池化复用线程的执行组件情况下提供ThreadLocal值的传递功能解决异步执行时上下文传递的问题。 最后说一句(求关注!别白嫖) 如果这篇文章对您有所帮助或者有所启发的话求一键三连点赞、转发、在看。 关注公众号woniuxgg在公众号中回复笔记  就可以获得蜗牛为你精心准备的java实战语雀笔记回复面试、开发手册、有超赞的粉丝福利
http://www.pierceye.com/news/18010/

相关文章:

  • 做离心开关的企业的网站衡水移动网站建设报价
  • 重庆网站建设leco tec微信端网站页面设计
  • 全景网站模版常德人才网
  • 中煤建设协会网站黑帽seo技术有哪些
  • 做音乐网站要注意什么网络项目平台
  • 有没有专门做花鸟鱼虫的网站网站默认图片素材
  • 利用分类信息网站做推广抖音seo优化排名
  • 茂名手机网站建设公司建好的网站怎么用
  • 大连网站制作学校iot物联网平台开发
  • 竞价网站和优化网站的区别你注册过的那些网站
  • 南宁住房和城乡建设局网站辽宁建设工程信息网盲盒系统
  • 曲靖高端网站制作产品做国外网站有哪些
  • 做一个网站每年多少钱天下商机创业网
  • asp做一个简单网站wordpress 图片名乱码
  • 如何做流量充值网站中信建设有限责任公司内部网站
  • 怎么做购物网站系统文本德阳网站怎么做seo
  • 网站模板 外贸工厂网页设计图
  • 建设网站呼叫中心有什么好处平面设计官方网站
  • 门户网站建设情况调研报告做下载类网站一年赚多少钱
  • 公司网站 cmswordpress 七牛图床
  • 咸阳市住房和城乡建设局网站别人用我公司权限做网站
  • 网站底部备案信息西安航投集团有限公司
  • 创办网站需要多少钱wordpress主题制作视频教程
  • 哪个做企业网站wordpress迁hexo
  • 炫酷表白网站在线制作wordpress有小方块
  • 中盛浩瀚建设有限公司网站注册个人网址
  • 青岛网站建设排名软件工程考研难度
  • 网站代运营推广网站运营推广方式
  • 站内seo内容优化包括个人网站建设优化
  • 南宁网站建设gxjzdrj长春昆仑建设股份有限公司网站