【高级JSE技术】线程池

引言

线程池是java并发技术中常用的一种,通过缓存线程资源避免了频繁的创建销毁线程带来的额外开销,从而提高性能。JDK中有相应的Executor框架实现,而Spring中也带有线程池的功能。本文将从以下几个角度来梳理线程池的用法和注意点:

  1. Executor框架

    1. 种类和特点
    2. Callable和Future
    3. 使用实例
  2. 使用Spring线程池

Executor框架

种类和特点

Java的Executor框架是专门设计用在以任务为单位的并发情景下的。以任务为单位的含义是:每次请求与请求之间互不关联,请求的结果不受其他请求的影响。这样可以将每个请求封装成一个个任务,交给Executor框架执行。举个例子,递归程序能否用Executor框架进行优化? 事实上一些递归程序的确可以用Executor框架进行优化,比如说归并排序,在合并阶段就可以并发的合并得到结果。但是某些递归程序就无法使用Executor来优化,比如说斐波那契求解,因为后一个结果需要依赖前一个结果,这样的任务是不独立的,无法切割。说了这么多,下面来看一个简单的使用例子:


public
class Executor {

public
static
void main(String[] args) {

Executor executor = Executors.newFixedThreadPool(10);

Runnable task = new Runnable() {

@Override

public
void run() {

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提供了大概以下这么几种创建线程池的方法:

  1. newFixThreadPool:创建一个固定大小的线程池,每次提交一个任务就生成一个线程,直到最大值,这时候如果某个线程发生Exception挂掉了再生成一个新的补上。
  2. newSingleThreadExecutor:只创建一个线程来执行任务,如果这个线程挂了则再次生成一个新的线程。这个线程池可以保证任务被串行的执行,适用于一些特殊的场景,如FIFO,优先级等。
  3. newCachedThreadPool:创建一个带缓冲的线程池,如果线程池的资源有剩余则回收,如果线程池资源紧张则再次添加。
  4. newScheduledThreadPool:创建一个固定大小的线程池,所有任务都是以定时或延时的方式进行的,类似Timer。

Callable和Future

Callable是一种和runable不同的任务接口,主要用于解决任务执行后需要放回结果的问题。从上面第一个例子我们可以看到runable的任务执行完后是没有返回结果的,这样在某些场景下是不适用的,比如说我需要存储100张图片,在存储的过程中可能会抛出异常导致存储失败。那么我需要在任务重捕获异常并且标记当前编号的图片存储失败,并且返回一个失败的标记。这时候就需要我们使用callable而不是runable。下面我们来看一个例子:


class TaskWithResult implements Callable<String> {

????private
int
id;

????public TaskWithResult(int id) {

????????this.id = id;

????}

????@Override

????public String call() throws Exception {

????????return
"result of TaskWithResult " + id;

????}

}

public
class CallableTest {

????public
static
void main(String[] args) throws InterruptedException,

????????????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类型的。

?

?

?

?

?

?

时间: 2024-12-16 20:21:07

【高级JSE技术】线程池的相关文章

池化技术——自定义线程池

目录 池化技术--自定义线程池 1.为什么要使用线程池? 1.1.池化技术的特点: 1.2.线程池的好处: 1.3.如何自定义一个线程池 2.三大方法 2.1.单个线程的线程池方法 2.2.固定的线程池的大小的方法 2.3.可伸缩的线程池的方法 2.4.完整的测试代码为: 3.为什么要自定义线程池?三大方法创建线程池的弊端分析 4.七大参数 5.如何手动的去创建一个线程池 6.四种拒绝策略 6.1.会抛出异常的拒绝策略 6.2.哪来的去哪里拒绝策略 6.3.丢掉任务拒绝策略 6.4.尝试竞争拒绝

Linux多线程实践(9) --简单线程池的设计与实现

线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利用已有对象来服务(不止一个不同的任务)就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因.比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同

Linux下简单线程池的实现

线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利用已有对象来服务(不止一个不同的任务)就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因.比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同

.NET线程池技术实现多任务批量处理

一.多线程技术应用场景介绍 本期同样带给大家分享的是阿笨在实际工作中遇到的真实业务场景,请跟随阿笨的视角去如何采用基于开源组件SmartThreadPool线程池技术实现多任务批量处理.在工作中您是否遇到过如何快速高效的处理Job任务列表.如何通过多线程批量处理订单.如何多线程群发短信.如何批量上传图片到远程图片服务器或者云存储图片服务器.如何通过多线程让应用程序提高对CPU的利用率从而增加应用程序的处理效率,等等.如果您有遇到类似的业务场景的而感到烦恼的话,那么今天您看完阿笨的分享课后下次碰到

线程(Thread)、线程池(ThreadPool)技术

线程:是Windows任务调度的最小单位.线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数,在一个应用程序中,常常需要使用多个线程来处理不同的事情,这样可以提高程序的运行效率,也不会使主界面出现无响应的情况.在这里主要介绍线程(Thread).线程池(ThreadPool)两种不同创建线程的区别 在通常的情况下,当我们需要开启一个新的线程时,我们直接通过Thread(继承自 System.Threading;)去创建

Java线程池技术以及实现

对于服务端而言,经常面对的是客户端传入的短小任务,需要服务端快速处理并返回结果.如果服务端每次接受一个客户端请求都创建一个线程然后处理请求返回数据,这在请求客户端数量少的阶段看起来是一个不错的选择,但是面对成千上万的请求在某一时段同时到达服务器时,如果还是采用这种方式,那么将会创建数以万计的线程,暂且不讨论线程是否会达到操作系统上限,单单操作系统频繁的进行线程的上下文切换就是一个巨大的开销,无故的增加的系统的负载,而线程的创建和消亡都是需要耗费系统资源的,也无疑造成了资源的浪费. 线程池技术就能

java线程池技术

1.线程池的实现原理?简介: 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间.如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能. 线程池技术正是关注如何缩短或调整T1.T3时间的技术,从而提高服务器程序性能的.它把T1.T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理

[并发]线程池技术小白

1  线程池技术介绍 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因.比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同样符合这一思想.

.NET 线程池编程技术

摘要 深度探索 Microsoft .NET提供的线程池, 揭示什么情况下你需要用线程池以及 .NET框架下的线程池是如何实现的,并告诉你如何去使用线程池. 内容 介绍 .NET中的线程池 线程池中执行的函数 使用定时器 同步对象的执行 异步I/O操作 监视线程池 死锁 有关安全性 结束 介绍 如果你有在任何编程语言下的多线程编程经验的话,你肯定已经非常熟悉一些典型的范例.通常,多线程编程与基于用户界面的应用联系在一起,它们需要在不影响终端用户的情况下,执行一些耗时的操作.取出任何一本参考书,打