【高级JSE技术】线程池
引言
线程池是java并发技术中常用的一种,通过缓存线程资源避免了频繁的创建销毁线程带来的额外开销,从而提高性能。JDK中有相应的Executor框架实现,而Spring中也带有线程池的功能。本文将从以下几个角度来梳理线程池的用法和注意点:
- Executor框架
- 种类和特点
- Callable和Future
- 使用实例
- 使用Spring线程池
Executor框架
种类和特点
Java的Executor框架是专门设计用在以任务为单位的并发情景下的。以任务为单位的含义是:每次请求与请求之间互不关联,请求的结果不受其他请求的影响。这样可以将每个请求封装成一个个任务,交给Executor框架执行。举个例子,递归程序能否用Executor框架进行优化? 事实上一些递归程序的确可以用Executor框架进行优化,比如说归并排序,在合并阶段就可以并发的合并得到结果。但是某些递归程序就无法使用Executor来优化,比如说斐波那契求解,因为后一个结果需要依赖前一个结果,这样的任务是不独立的,无法切割。说了这么多,下面来看一个简单的使用例子:
|
public public Executor executor = Executors.newFixedThreadPool(10); Runnable task = new Runnable() { @Override public System.out.println("task over"); } }; executor.execute(task); executor = Executors.newScheduledThreadPool(10); ScheduledExecutorService scheduler = (ScheduledExecutorService) executor; scheduler.scheduleAtFixedRate(task, 10, 10, TimeUnit.SECONDS); } } |
其中 Executors是Executor, ExecutorService, ScheduledExecutorService, ThreadFactory, 和 Callable的工厂。他提供一系列的静态方法来获取特定的线程池,这些线程池的功能各有特点,下面我们来看一下Executors的OutLine:

我们可以看到Executors提供了大概以下这么几种创建线程池的方法:
- newFixThreadPool:创建一个固定大小的线程池,每次提交一个任务就生成一个线程,直到最大值,这时候如果某个线程发生Exception挂掉了再生成一个新的补上。
- newSingleThreadExecutor:只创建一个线程来执行任务,如果这个线程挂了则再次生成一个新的线程。这个线程池可以保证任务被串行的执行,适用于一些特殊的场景,如FIFO,优先级等。
- newCachedThreadPool:创建一个带缓冲的线程池,如果线程池的资源有剩余则回收,如果线程池资源紧张则再次添加。
- newScheduledThreadPool:创建一个固定大小的线程池,所有任务都是以定时或延时的方式进行的,类似Timer。
Callable和Future
Callable是一种和runable不同的任务接口,主要用于解决任务执行后需要放回结果的问题。从上面第一个例子我们可以看到runable的任务执行完后是没有返回结果的,这样在某些场景下是不适用的,比如说我需要存储100张图片,在存储的过程中可能会抛出异常导致存储失败。那么我需要在任务重捕获异常并且标记当前编号的图片存储失败,并且返回一个失败的标记。这时候就需要我们使用callable而不是runable。下面我们来看一个例子:
|
class TaskWithResult implements Callable<String> { private public TaskWithResult(int id) { this.id = id; } @Override public String call() throws Exception { return } } public public ExecutionException { ExecutorService exec = Executors.newCachedThreadPool(); ArrayList<Future<String>> results = new ArrayList<Future<String>>(); for (int i = 0; i < 10; i++) results.add(exec.submit(new TaskWithResult(i))); for (Future<String> fs : results) { if (fs.isDone()) System.out.println(fs.get()); else System.out.println("Future result is not yet complete"); } exec.shutdown(); } } |
上面的代码首先是TaskWithResult实现了callable的接口,重写了call方法,返回一段字符串。Main里面生成了一个CachedThreadPool,下面这句是重点,results.add(exec.submit(new TaskWithResult(i))) 它做了三件事,一生成一个callable的任务,二提交给线程池,三将结果加入results队列。Results是一个future类型的队列,什么事future类型呢?简单来讲future 相当于是用来存放Executor执行的结果的一种泛型容器,上述例子中我们生成了一个String类型的结果容器,所以要求返回的结果是String类型的。
【高级JSE技术】线程池的更多相关文章
- 自定义高级版python线程池
基于简单版创建类对象过多,现自定义高级版python线程池,代码如下 #高级线程池 import queue import threading import time StopEvent = obje ...
- elasticsearch高级配置二----线程池设置
一个Elasticsearch节点会有多个线程池,但重要的是下面四个: 索引(index):主要是索引数据和删除数据操作(默认是cached类型) 搜索(search):主要是获取,统计和搜索操作(默 ...
- 隔离技术线程池(ThreadPool)和信号量(semaphore)
一.首先要明白Semaphore和线程池各自是干什么? 信号量Semaphore是一个并发工具类,用来控制可同时并发的线程数,其内部维护了一组虚拟许可,通过构造器指定许可的数量,每次线程执行操作时先通 ...
- Linux多线程实践(9) --简单线程池的设计与实现
线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以 ...
- 使用C++11实现一个半同步半异步线程池
前言 C++11之前我们使用线程需要系统提供API.posix线程库或者使用boost提供的线程库,C++11后就加入了跨平台的线程类std::thread,线程同步相关类std::mutex.std ...
- 温故知新-java多线程&深入理解线程池
文章目录 摘要 java中的线程 java中的线程池 线程池技术 线程池的实现原理 简述 ThreadPoolExecutor是如何运行的? 线程池运行的状态和线程数量 任务执行机制 队列缓存 Wor ...
- 第45天学习打卡(Set 不安全 Map不安全 Callable 常用的辅助类 读写锁 阻塞队列 线程池)
Set不安全 package com.kuang.unsafe; import java.util.*; import java.util.concurrent.CopyOnWriteArray ...
- JUI(6)线程池
文章目录 1.SynchronousQueue 2.线程池(重点) 2.1 使用单例 2.2.使用固定大小的线程 2.3.缓存线程池 2.4 七大参数 1.SynchronousQueue packa ...
- java线程池技术(二): 核心ThreadPoolExecutor介绍
版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程池技术属于比较"古老"而又比较基础的技术了,本篇博客主要作用是个人技术梳理,没什么新玩意. 一.Java线程池技术的 ...
随机推荐
- Ngrok,一款可以帮助你展示网站和联网开发的工具
使用Ngrok的目的就是为了可以让别人通过网络访问到自己本机上的项目 下面是一个简单的使用教程,详细的查看官网英文文档. 第一步: 登录官网:https://ngrok.com/ 注册或者登录 ...
- windows主机mysql忘记密码如何重置
本文主要是针对mysql重置密码过程中出现“mysqld不是内部命令或外部命令”的问题而写的.网上有很多关于mysql忘记密码了如何找回的文章,但是很多说的都不够详细,特别是还要用到DOS命令,可能这 ...
- Javascript(jQuery)中绑定页面上所有按钮点击事件的几种方式
方法一:使用document对象查找所有的按钮 [javascript] view plain copy 在CODE上查看代码片派生到我的代码片 //按照dom的方式添加事件处理 function B ...
- cocos2d-x中,简单html富文本显示
作者:HU 转载请注明,原文链接:http://www.cnblogs.com/xioapingguo/p/4037414.html 虽然自从cocos2d-x更新到3.0后,使用freetype, ...
- #Cocos2d+lua#android+Eclipse工程编译设置
用Elicpse编译cocos2d+lua的工程几点注意点记录: 1.设置工程属性Windows->Preferences->NDK目录 2.右键Android Tools->Add ...
- Genymotion - 强大好用高性能的 Android 模拟器 (在电脑流畅运行APK安卓软件游戏的利器)
随着 Android 系统的应用和游戏越来越丰富,甚至有些比起Windows.Mac上的软件更加好用好玩,因此很多人都希望能在电脑上也能玩到安卓的游戏或APP. 我们曾推荐过 BlueStacks,而 ...
- 【22】将成员变量声明为private
1.为什么要将成员变量声明为private,语法一致性,只通过方法暴露接口. 2.使用方法,可以对成员变量更精确的控制.比如:为所有可能的实现提供弹性,不同实现可以替换:控制可读可写:验证约束条件:处 ...
- 设计模式之十三:适配器模式(Adapter)
适配器模式: 将一个类的接口转换成另外一个期望的类的接口.适配器同意接口互不兼容的类一起工作. Convert the interface of a class into another interf ...
- HDU 1330 Nearest Common Ancestors(求两个点的近期公共祖先)
题目链接:id=1330">传送门 在线算法: #include <iostream> #include <cstdio> #include <cstri ...
- nginx,linux压力测试工具webbench
webbench最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好,安装使用也特别方便. 1.适用系统:Linux 2.编译安装: 1. wget htt ...