博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java并发编程——线程池和Executor介绍
阅读量:2393 次
发布时间:2019-05-10

本文共 3516 字,大约阅读时间需要 11 分钟。

  • 第一部分:概述

早期的应用程序大多是单线程串行执行的,虽然程序的任务边界清晰有序,但是执行的效率却很低,尤其是执行花费时间较长的操作,会导致大量的等待和堆积。为了提高程序的执行效率和吞吐量,我们很自然的会想到多线程,即为每个任务都新建一个独立的线程,这样就极大地提高了程序的执行效率。但事实上多线程也会带来很多问题。比如大量的创建线程,这本身就会消耗很多的资源,尤其是内存,当创建的线程数量超过服务器能够承受的极限时,内存溢出是在所难免的;比如还有其他稳定性问题,以及多线程造成的程序调用和管理的混乱。所以,综上所述,我们需要一个介于两者之间的工具,既可以创建大量的线程来提高程序的并发性和吞吐量,同时又可以有序的管理这些线程,能够可控。而Executor接口和线程池技术就是在这种背景下应运而生的。下面分别将这两种常用的并发技术做以介绍和总结。

  • 第二部分:Executor和ExecutorService接口介绍

java.util.coucurrent包下面为我们提供了丰富的并发工具,Executor和ExecutorService接口就是其中比较重要的两个。

  • Executor接口介绍

public interface Executor{    void execute(Runnable command);}

以上是Executor接口的代码,可以看出这个借口非常简单,就只有一个execute()方法。但他却为强大的异步任务执行提供了基础,它支持不同类型的任务执行策略。Executor框架基于生产者消费者模型,它提供了一个标准的方法将任务的提交和任务的执行过程解耦,并用Runnable来表示任务。下面来看一个基于Executor的简单服务器实现:

public class ExecutorWebServer {    private static final int LIMIT = 50;    private static final Executor exe = Executors.newFixedThreadPool(LIMIT);    	public static void main(String[] args) throws IOException {		// TODO Auto-generated method stub        ServerSocket server = new ServerSocket(80);        while(true){        	Socket socket = server.accept();        	Runnable task = new Runnable(){        		public void run(){        			doSomeThing(socket);        		}        	};        	exe.execute(task);        }	}}

通过上面列子我们就很好的把任务的提交和任务的执行分开来,这就是Executor框架最大的优势。

  • ExecutorService接口介绍

上面我们讲了如何创建一个Executor,但是并没有讲如何关闭它。既然Executor是为应用程序服务的,因而他们应该是可关闭的,并将关闭操作中受影响的任务状态反馈给应用程序。为了解决执行服务的生命周期问题,ExecutorService扩展了Executor接口,增加了管理生命周期的方法:

public interface ExecutorService Extends Executor{    void shutdown();    boolean isShutDown();    boolean isTerminated();    ……}

ExecutorService的生命周期分为三种,运行,关闭和已终止。下面看这个简单的实例:

class NetworkService implements Runnable {    private final ServerSocket serverSocket;    private final ExecutorService pool;    public NetworkService(int port, int poolSize)        throws IOException {      serverSocket = new ServerSocket(port);      pool = Executors.newFixedThreadPool(poolSize);    }     public void run() { // run the service      try {        for (;;) {          pool.execute(new Handler(serverSocket.accept()));        }      } catch (IOException ex) {        pool.shutdown();      }    }  }  class Handler implements Runnable {    private final Socket socket;    Handler(Socket socket) { this.socket = socket; }    public void run() {      // read and service request on socket    } }
  • 第三部分:线程池介绍及使用

  • 几种类型的线程池

可以通过Executors类的几个静态方法来创建线程池。包含以下几类线程池:

newFixedThreadPool创建固定长度的线程池。每提交一个任务时就新建一个线程,直到达到线程池的最大数量。

newCachedThreadPool创建一个可缓存的线程池,线程的数量不受限制,但是在以前线程可用时将重用他们。

newSingleThreadExecutor创建一个使用单个 worker 线程的 ,以无界队列方式来运行该线程。

newScheduleThreadPool创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。类似于一个定时器。

  • 设置线程池大小

线程池的理想大小取决于被提交任务的类型以及所部署系统的特性。在代码中最好不要固定线程池的大小,而要通过某种灵活机制来配置。线程池大小的配置只要避免“过大”和”过小“两种极端情况即可。线程池过大会导致大量的线程竞争CPU和内存,最终导致资源耗尽;线程池过小时又会导致资源浪费,所以设置一个合适的线程池大小非常重要。通常有一个简单的设置线程池大小的公式供我们参考使用:

N(Threads) = N(cpu) * U(cpu) * (1 + w/c)

N(cpu)代表cpu的个数,U(cpu)代表cpu利用率, w/c表示等待时间与计算时间的比值

  • 配置线程池

ThreadPoolExecutor为Executor和ExecutorService接口提供了基本实现。下面我们来看一下ThreadPoolExecutor类的构造函数:该类一共有四个构造函数,其中最基础的一个构造函数如下:

ThreadPoolExecutor(int corePoolSize,                    int maximumPoolSize,                    long keepAliveTime,                    TimeUnit unit,                    BlockingQueue
workQueue)

corePoolSize表示的是核心池的大小,第二个参数表示线程池最大的线程数,第三个参数表示存活时间,第四个参数表示给定单元粒度的时间段,第五个参数表示的是工作队列。

  • 扩展线程池

ThreadPoolExecutor是可以扩展的,它提供了几个可以在子类中改写的方法:beforeExecutor,afterExecutor,terminated,这些方法可用于扩展ThreadPoolExecutor的行为。

 

转载于:https://my.oschina.net/powerisam/blog/681443

你可能感兴趣的文章
windows7配置虚拟AP的脚本
查看>>
北京开放政府信息资源 “大数据”供社会化利用
查看>>
大数据挖掘变革 美赛达软硬云引领车联网商业蓝海
查看>>
停车费上涨需要公开“大数据”
查看>>
DirectFB代码导读
查看>>
Cocos2dx3.2从零开始【四】继续。
查看>>
sphinx教程2__安装、配置和使用
查看>>
Discuz!$_G变量的使用方法
查看>>
《云计算架构技术与实践》序言(李德毅院士)
查看>>
how to use this bugs unserialize()
查看>>
Defeating SSL using SSLStrip (Marlinspike Blackhat)
查看>>
大型网站数据库架构
查看>>
rdp 安全策略
查看>>
Threat Intelligence Quotient Test
查看>>
Cisco路由器上防止DDOS的一些建议
查看>>
系统安全防护之UNIX下入侵检测方法
查看>>
域控渗透技巧
查看>>
Minion security project and 分布式nmap
查看>>
网络性能测试工具Iperf上手指南
查看>>
opensecuritytraining video
查看>>