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

做暖dnf动态ufo网站网页设计制作心得体会

做暖dnf动态ufo网站,网页设计制作心得体会,上海企业注销流程,贸易公司取什么名字无论您是否知道#xff0c;您的Java Web应用程序很可能都使用线程池来处理传入的请求。 这是许多人忽略的实现细节#xff0c;但是迟早您需要了解如何使用该池以及如何为您的应用程序正确调整池。 本文旨在说明线程模型#xff0c;什么是线程池以及正确配置线程池所需执行的… 无论您是否知道您的Java Web应用程序很可能都使用线程池来处理传入的请求。 这是许多人忽略的实现细节但是迟早您需要了解如何使用该池以及如何为您的应用程序正确调整池。 本文旨在说明线程模型什么是线程池以及正确配置线程池所需执行的操作。 单螺纹 让我们从一些基础知识开始并随着线程模型的发展而前进。 无论您使用哪种应用程序服务器或框架 Tomcat Dropwizard Jetty 它们都使用相同的基本方法。 一个深埋在Web服务器内部的套接字。 该套接字正在侦听传入的TCP连接并接受它们。 一旦被接受就可以从新建立的TCP连接中读取数据进行解析并将其转换为HTTP请求。 然后将此请求移交给Web应用程序以完成其所需的操作。 为了理解线程的作用我们将不使用应用程序服务器而是从头开始构建一个简单的服务器。 该服务器反映了大多数应用程序服务器的功能。 首先单线程Web服务器可能看起来像这样 ServerSocket listener new ServerSocket(8080); try {while (true) {Socket socket listener.accept();try {handleRequest(socket);} catch (IOException e) {e.printStackTrace();}} } finally {listener.close(); } 此代码在端口8080上创建一个ServerSocket 然后在一个紧密循环中ServerSocket检查是否接受新连接。 一旦接受套接字将传递给handleRequest方法。 该方法通常将读取HTTP请求执行所需的任何过程然后编写响应。 在此简单示例中handleRequest读取一行并返回简短的HTTP响应。 handleRequest做一些更复杂的事情是正常的例如从数据库中读取或进行某种其他类型的IO。 final static String response “HTTP/1.0 200 OK\r\n” “Content-type: text/plain\r\n” “\r\n” “Hello World\r\n”;public static void handleRequest(Socket socket) throws IOException {// Read the input stream, and return “200 OK”try {BufferedReader in new BufferedReader(new InputStreamReader(socket.getInputStream()));log.info(in.readLine());OutputStream out socket.getOutputStream();out.write(response.getBytes(StandardCharsets.UTF_8));} finally {socket.close();} } 由于只有一个线程处理所有接受的套接字因此在接受下一个请求之前必须完全处理每个请求。 在实际的应用程序中等效的handleRequest方法返回大约100毫秒的时间可能是正常的。 如果是这种情况服务器将被限制为每秒仅处理10个请求一个接一个。 多线程 即使handleRequest可能在IO上被阻止CPU也可以自由处理更多请求。 使用单线程方法是不可能的。 因此可以通过创建多个线程来改进此服务器以允许并发操作 public static class HandleRequestRunnable implements Runnable {final Socket socket;public HandleRequestRunnable(Socket socket) {this.socket socket;}public void run() {try {handleRequest(socket);} catch (IOException e) {e.printStackTrace();}} }ServerSocket listener new ServerSocket(8080); try {while (true) {Socket socket listener.accept();new Thread(new HandleRequestRunnable(socket)).start();} } finally {listener.close(); } 在这里仍然在单个线程内的紧密循环中调用accept但是一旦接受TCP连接并且有可用的套接字就会产生一个新线程。 这个产生的线程执行一个HandleRequestRunnable它从上面简单地调用相同的handleRequest方法。 创建新线程后现在可以释放原始的accept线程来处理更多的TCP连接并允许应用程序同时处理请求。 该技术被称为“每个请求线程”是最流行的方法。 值得注意的是还有其他方法例如事件驱动的异步模型NGINX和Node.js部署但是它们不使用线程池因此不在本文讨论范围之内。 在“每个请求的线程”方法中创建新线程然后销毁它可能会很昂贵因为JVM和OS都需要分配资源。 另外在上述实现中正在创建的线程数不受限制。 不受限制是很成问题的因为它会很快导致资源枯竭。 资源枯竭 每个线程都需要一定数量的内存用于堆栈。 在最新的64位JVM上 默认堆栈大小为1024KB。 如果服务器收到大量请求或者handleRequest方法变慢则服务器可能会出现大量并发线程。 因此要管理1000个并发请求仅用于线程堆栈的1000个线程将消耗1GB的JVM RAM。 另外在每个线程中执行的代码将在处理请求所需的堆上创建对象。 这非常Swift地加起来并且可能超过分配给JVM的堆空间从而对垃圾收集器施加压力从而导致崩溃并最终导致OutOfMemoryErrors 。 线程不仅消耗RAM而且可能使用其他有限资源例如文件句柄或数据库连接。 超过这些可能导致其他类型的错误或崩溃。 因此为了避免耗尽资源重要的是避免无限制的数据结构。 不是灵丹妙药但是可以通过使用-Xss标志调整堆栈大小来缓解堆栈大小问题。 较小的堆栈将减少每个线程的开销但可能导致StackOverflowErrors 。 您的里程会有所不同但是对于许多应用程序默认的1024KB过多因此较小的256KB或512KB值可能更合适。 Java允许的最小值是16KB。 线程池 为了避免连续创建新线程并限制最大数量可以使用简单的线程池。 简而言之该池跟踪所有线程在需要达到上限时创建新线程并在可能的情况下重用空闲线程。 ServerSocket listener new ServerSocket(8080); ExecutorService executor Executors.newFixedThreadPool(4); try {while (true) {Socket socket listener.accept();executor.submit( new HandleRequestRunnable(socket) );} } finally {listener.close(); } 现在此代码不是直接创建线程而是使用ExecutorService该服务提交要在线程池中执行的工作用Runnables术语。 在此示例中四个线程的固定线程池用于处理所有传入的请求。 这限制了“进行中”请求的数量因此限制了资源的使用。 除了newFixedThreadPool之外 Executors实用程序类还提供了newCachedThreadPool方法。 这受到较早的无限线程数量的困扰但是只要有可能就利用先前创建但现在空闲的线程。 通常这种类型的池对于不会阻塞外部资源的短暂请求很有用。 ThreadPoolExecutors可以直接构造从而可以自定义其行为。 例如可以定义池中线程的最小和最大数量以及何时创建和销毁线程的策略。 简短的示例。 工作队列 在固定线程池的情况下细心的读者可能想知道如果所有线程都忙并且有新请求进入会发生什么情况。那么ThreadPoolExecutor使用队列来容纳线程可用之前的待处理请求。 默认情况下Executors.newFixedThreadPool和Executors.newCachedThreadPool都使用无界LinkedList。 再次这会导致资源耗尽问题尽管速度要慢得多因为每个排队的请求都小于完整线程并且通常不会使用那么多资源。 但是在我们的示例中每个排队的请求都持有一个套接字取决于OS将占用一个文件句柄。 这是操作系统将限制的资源类型因此除非有必要否则最好不要保留它。 因此限制工作队列的大小也很有意义。 public static ExecutorService newBoundedFixedThreadPool(int nThreads, int capacity) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueueRunnable(capacity),new ThreadPoolExecutor.DiscardPolicy()); }public static void boundedThreadPoolServerSocket() throws IOException {ServerSocket listener new ServerSocket(8080);ExecutorService executor newBoundedFixedThreadPool(4, 16);try {while (true) {Socket socket listener.accept();executor.submit( new HandleRequestRunnable(socket) );}} finally {listener.close();} } 同样我们创建了一个线程池但是我们没有使用Executors.newFixedThreadPool帮助器方法而是自己创建了ThreadPoolExecutor并传递了一个限制为16个元素的有界LinkedBlockingQueue 。 或者可以使用ArrayBlockingQueue 它是有界缓冲区的实现。 如果所有线程都忙并且队列已满则下一步将由ThreadPoolExecutor的最后一个参数定义。 在此示例中使用了DiscardPolicy 它仅丢弃将使队列溢出的所有工作。 还有其他政策如AbortPolicy它抛出一个异常或CallerRunsPolicy执行该调用者的线程上的工作。 该CallerRunsPolicy提供了一种简单的方法来自我限制可以添加作业的速率但是这可能是有害的阻塞了一个应保持畅通的线程。 一个好的默认策略是“放弃”或“中止”这两者都会放弃工作。 在这些情况下很容易向客户端返回一个简单的错误例如HTTP 503“服务不可用” 。 有人会争辩说只是增加队列大小然后所有工作最终都会运行。 但是用户不愿永远等待如果从根本上说工作的执行速度超过了可以执行的速度那么队列将无限期地增长。 相反该队列仅应用于消除突发请求或处理处理中的短暂停顿。 在正常操作中队列应为空。 有多少个线程 现在我们了解了如何创建线程池困难的问题是应该有多少个线程可用 我们确定最大数量应该限制为不导致资源耗尽。 这包括所有类型的资源内存堆栈和堆打开的文件句柄打开的TCP连接远程数据库可以处理的连接数以及任何其他有限资源。 相反如果线程是CPU绑定的而不是IO绑定的则应将物理核心的数量视为有限并且每个核心最多只能创建一个线程。 这一切都取决于应用程序正在做的工作。 用户应使用各种池大小和实际的请求混合来运行负载测试。 每次增加它们的线程池大小直到断点。 这样就可以找到资源耗尽时的上限。 在某些情况下明智的做法是增加可用资源的数量例如为JVM提供更多的RAM或调整OS以允许更多的文件句柄。 但是在某个时候将达到理论上限应该注意但这还不是故事的结局。 利特尔定律 排队论尤其是利特尔定律 可以用来帮助理解线程池的属性。 简单来说利特尔定律描述了三个变量之间的关系。 L进行中的请求数量λ新请求到达的速率W平均处理请求的时间。 例如如果每秒有10个请求到达并且每个请求花费一秒钟的时间来处理则在任何时间平均有10个正在进行的请求。 在我们的示例中这映射为使用10个线程。 如果处理单个请求的时间增加了一倍则运行中的平均请求数也将增加一倍达到20因此需要20个线程。 了解执行时间对进行中的请求的影响非常重要。 某些后端资源例如数据库停顿是很常见的导致请求花费更长的时间来处理从而很快耗尽了线程池。 因此理论上限可能不是池大小的适当限制。 相反应该对执行时间设置一个限制并与理论上限结合使用。 例如假设在JVM超过其内存分配之前可以处理的最大传输中请求为1000。 如果我们预算每个请求的时间不超过30秒那么在最坏的情况下我们应该期望每秒处理不超过33个请求。 但是如果一切正常并且请求仅用500毫秒即可处理则应用程序每秒只能在1000个线程上处理2000个请求。 指定可以使用队列来消除短暂的延迟突发也可能是合理的。 为什么要麻烦 如果线程池中的线程太少则存在以下风险资源利用不足不必要地将用户拒之门外。 但是如果允许太多线程则会发生资源耗尽这可能会造成更大的破坏。 不仅会耗尽本地资源还可能对其他资源产生不利影响。 例如多个应用程序查询同一个后端数据库。 数据库通常对并发连接数有硬性限制。 如果一个行为异常的应用程序消耗了所有这些连接它将阻止其他应用程序访问数据库。 造成大范围的中断。 更糟糕的是可能会发生级联故障。 想象一下一个环境其中有一个应用程序的多个实例位于一个公共负载均衡器的后面。 如果实例之一由于正在进行的请求过多而开始用尽内存那么JVM将花费更多时间进行垃圾收集并减少处理请求的时间。 这种减慢速度将降低该实例的容量并迫使其他实例处理更高比例的传入请求。 随着他们现在使用其无限制线程池处理更多请求会发生相同的问题。 它们耗尽了内存然后再次开始积极地进行垃圾回收。 这个恶性循环在所有实例之间级联直到出现系统性故障。 我经常观察到没有进行负载测试并且允许任意数量的线程。 在通常情况下应用程序可以使用少量线程以传入速率愉快地处理请求。 但是如果处理请求取决于远程服务并且该服务暂时变慢则W的增加平均处理时间的影响会很快耗尽池。 由于从未对应用程序进行最大数量的负载测试因此会出现之前概述的所有资源耗尽问题。 有多少个线程池 在微 服务或面向服务的体系结构 SOA中访问多个远程后端服务是正常的。 此设置特别容易发生故障因此应仔细解决这些问题。 如果远程服务的性能下降则可能导致线程池快速达到其极限从而丢弃后续请求。 但是并非所有请求都可能需要此不正常的后端但是由于线程池已满因此不必要地删除了这些请求。 通过提供特定于后端的线程池可以隔离每个后端的故障。 在这种模式下仍然只有一个请求工作程序池但是如果请求需要调用远程服务则工作将转移到该后端的线程池。 这使主请求池不会受到单个缓慢后端的负担。 这样只有需要特定后端池的请求才会在故障时受到影响。 多个线程池的最后一个好处是它有助于避免某种形式的死锁。 如果由于尚未处理的请求而导致每个可用线程都被阻塞则将发生死锁并且没有线程可以前进。 当使用多个池并充分了解它们执行的工作时可以在某种程度上缓解此问题。 截止日期和其他最佳做法 常见的最佳做法是确保所有远程呼叫都有最后期限。 也就是说如果远程服务在合理时间内没有响应则该请求将被放弃。 可以在线程池中使用相同的技术。 具体来说如果线程正在处理一个请求的时间超过了定义的期限则应终止该线程。 为新请求腾出空间并在W上设置上限。这似乎是一种浪费但是如果用户通常是Web浏览器正在等待响应则30秒后浏览器可能只会给出无论如何还是用户可能会变得急躁并离开。 快速失败是在为后端创建池时可以采用的另一种方法。 如果后端发生故障则线程池将Swift填充等待连接到无响应后端的请求。 相反可以将后端标记为不正常所有后续请求都可能立即失败而不是不必要地等待。 但是请注意需要一种机制来确定后端何时再次恢复健康。 最后如果一个请求需要独立地调用多个后端则应该可以并行而不是顺序地调用它们。 这将减少等待时间但以增加线程为代价。 幸运的是有一个很棒的库hystrix 它打包了许多这些最佳实践并以简单安全的方式公开了它们。 结论 希望本文能增进您对线程池的了解。 通过了解应用程序的需求并结合使用最大线程数和平均响应时间可以确定适当的线程池。 这不仅可以避免级联故障而且可以帮助计划和配置您的服务。 即使您的应用程序可能未显式使用线程池但它们还是被应用程序服务器或更高级别的抽象隐式使用。 Tomcat JBoss Undertow Dropwizard都为其线程池执行servlet的池提供了多个可调参数。 翻译自: https://www.javacodegeeks.com/2015/12/importance-tuning-thread-pools.html
http://www.sadfv.cn/news/229302/

相关文章:

  • 常州市中大建设工程有限公司网站建筑网络工程教程
  • 营销型网站审定标准建设网站需要准备什么手续
  • 做的网站打不开百度网址是多少
  • jsp网站 值班功能微信h5页面制作小程序
  • 电子商务网站开发计划书中学生在哪里学编程最好
  • 淘宝做导航网站有哪些功能网站源模板
  • 做网站每天任务及实训过程安卓排名优化
  • 分销平台网站建设如何打造网站
  • 宜昌商城网站建设阳江房产网签
  • 怎么给网站做备案做视频网站什么平台好
  • 怎样提高网站转化率网站接入服务提供商
  • 免费空间网站怎么做的建设银行移动门户网站
  • 网站里添加百度地图企业展厅设计公司哪家好怎么样
  • 网站推广站群晖wordpress只能访问首页
  • 找人做彩票网站有哪些平面设计师必看的网站
  • 网站友情链接购买网站dns
  • 网站平台建设所需开发工具seo上海培训
  • asp.net网站开发 pdf网址信息查询
  • 文本文档写入代码做网站网站定制设计价目表
  • 网站开发翻译站长之家域名查询
  • 很有风格的网站有哪些二百块做网站
  • 网站建设大型企业跨境电商一件代发货源平台
  • 微网站下载资料怎么做亳州公司做网站
  • 响应式网站例子wordpress使用json
  • seo网站推广的主要目的是什么如何做电影下载网站
  • 网站图片素材下载全屏网站设计技巧
  • 电子商务网站建设主管的策划书南通网站关键字优化
  • 东莞企业网站设计公司淘宝客如何建立自己的网站
  • 怎么用ps做网站首页背景图片本周新闻热点
  • 淮南微信网站建设河北网络推广平台