一. Java中的线程池

线程池的作用:

1. 降低资源消耗

2. 提高响应速度

3. 提高线程的可管理性

线程池处理流程:

1. 线程池判断核心线程池线程是否都在执行任务,如果不是,则创建一个新的工作线程来执行任务,如果核心线程池线程都在执行任务,则进入下一个流程。

2. 线程池判断工作队列是否已经满。如果工作队列未满,则将提交的任务存储在这个工作队列里,如果工作队列满了,则进入下一个流程。

3. 判断线程池的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务,如果已经都处于工作状态,则交给饱和策略来处理这个任务。

二. 线程池的使用

1. 创建线程池

通过ThreadPoolExecutor创建线程池

new ThreadPoolExecutor(corePoolSize, maximumPoolSize, KeepAliveTime, millisecounds, runnableTaskQueue, handler)

参数说明:

(1). corePoolSize :核心线程池大小

当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其它空闲线程能够执行任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用线程池的parstartAllCoreThreads()方法,线程池会提前创建并启动所有基本线程。

(2). runnableTaskQueue:任务队列

用于保存等待执行的任务的阻塞队列。可选的阻塞队列有:

<1>. ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,先进先出原则对元素进行排序

<2>. LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按照先进先出原则,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。

<3>. SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常高于LinkedBlockingQueue。静态工厂方法Executors.newCachedThreadPool使用了这个队列

<4>. PriorityBlockingQueue:一个具有优先级的无界阻塞队列

(3). maximumPoolSize:线程最大的数量

线程池允许创建的最大线程数量。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。

注意:如果使用了无界任务队列这个参数就没有什么效果

(4). ThreadFactory : 用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置有意思的名字。使用开源框架guava提供的ThreadFactoryBuilder可以快速给线程池里面线程设置有意思的名字

new ThreadFactoryBuilder().setNameFormat("XX-task-%d").build();

(5). RejectedExecutionHandler: 饱和策略

当队列和线程都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时就抛出异常,在Jdk1.5 中Java线程框架提供4种策略

<1>. AbortPolicy : 直接抛出异常

<2>. CallerRunsPolicy: 只用调用者所在线程来运行任务

<3>. DiscardOldestPolicy: 丢弃队列里最近的一个任务,并执行当前任务

<4>. DiscardPolicy:不处理,丢弃掉

也可以根据应用场景实现RegectedExecutionHandler接口自定义策略

(6). keepAliveTime:线程活动的保持时间

线程池的工作线程空闲后,保存存活的时间。如果任务很多,并且每个任务执行的时间比较短,可以调大时间,提高线程的利用率

(7). TimeUnit:线程活动保持时间单位

可选单位有天【DAYS】、小时 【HOURS】、分钟【MINUTES】、毫秒【MILLISECONDS】、微妙【MICROSECONDS】、纳秒【NANOSECONDS】

2. 向线程池提交任务

有两种方法可以向线程提交任务,分别为execute()和submit()方法

(1). execute()用于提交不需要返回值的任务,所以无法判断任务是否被线程执行成功

package com.bochao.concurrency;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; public class ThreadPool { public static void main(String[] args) { ExecutorService threadPool = new ThreadPoolExecutor(10, 20, 10, TimeUnit.SECONDS, null); threadPool.execute(new Runnable() { @Override
public void run() {
System.out.println("执行任务代码");
}
});
} }

(2). submit()用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获得返回值,get()方法会阻塞当前线程直到任务完成,而使用get(long timeout, timeUnit unit)方法则会阻塞当前线程一段时间,这时候有可能任务没有执行完成。

package com.bochao.concurrency;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; public class ThreadPool { public static void main(String[] args) { ExecutorService threadPool = new ThreadPoolExecutor(10, 20, 10, TimeUnit.SECONDS, null); Callable<Object> harReturnValuetask = null; Future<Object> future = threadPool.submit(harReturnValuetask); try {
Object o = future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
} } }

3. 关闭线程池

可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池。

它们的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。

区别:

(1). shutdownNow首先将线程设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待任务执行任务列表。而shutdown只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。

只要调用了这两个方法中的任意一个,isShutdown方法就会返回true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown方法来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow方法。

4. 合理的配置线程池

合理的配置线程池,必须要分析任务特性,可以从以下几个角度分析

(1). 任务的性质:CPU的密集型任务,IO密集型任务和混合型任务。

CPU密集型任务应配置尽可能小的线程,如可配置N(cpu数) + 1的线程池。

IO密集型任务线程并不是一直在执行任务,则应配置尽可能多的线程,如2*N(cpu数)。

混合型任务如果可以拆分可分为一个CPU密集型任务和一个IO密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行吞吐量将高于串行执行的吞吐量。如果这两个任务执行的时间相差很大,则没有必要进行分解。可以通过Runtime.getRuntime().availableProcessors()方法获得当前设备的CPU个数。

优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理。它可以让优先级高的任务先执行。

(2). 任务的优先级:高、中、低

(3). 任务的执行时间:长、中、短

(4). 任务的依赖性:是否依赖其它系统资源,如数据库连接池

5. 线程池的监控

由于大量的使用线程池,所以很有必要对其进行监控

(1). taskCount:线程池需要执行的任务数量

(2). completedTaskCount:线程池在运行过程中已完成的任务数量,小于或等于taskCount

(3). largestPoolSize: 线程池里曾经创建过最大的线程数量。通过这个数据可以知道线程池是否曾经满过。如该数值等于线程池最大大小,则表示线程池曾经满过。

(4). getPoolSize:线程池的线程数量。如果线程池不销毁的话,线程池里的线程不会自动销毁,所以这个大小只增不减。

(5). getActiveCount:获取活动的线程数

Java多线程基础知识(六)的更多相关文章

  1. Java 多线程——基础知识

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  2. Java 多线程基础(六)线程等待与唤醒

    Java 多线程基础(六)线程等待与唤醒 遇到这样一个场景,当某线程里面的逻辑需要等待异步处理结果返回后才能继续执行.或者说想要把一个异步的操作封装成一个同步的过程.这里就用到了线程等待唤醒机制. 一 ...

  3. Java多线程基础知识笔记(持续更新)

    多线程基础知识笔记 一.线程 1.基本概念 程序(program):是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码,静态对象. 进程(process):是程序的一次执行过程,或是 ...

  4. Java多线程基础知识总结

    2016-07-18 15:40:51 Java 多线程基础 1. 线程和进程 1.1 进程的概念 进程是表示资源分配的基本单位,又是调度运行的基本单位.例如,用户运行自己的程序,系统就创建一个进程, ...

  5. Java多线程基础知识篇

    这篇是Java多线程基本用法的一个总结. 本篇文章会从一下几个方面来说明Java多线程的基本用法: 如何使用多线程 如何得到多线程的一些信息 如何停止线程 如何暂停线程 线程的一些其他用法 所有的代码 ...

  6. JAVA多线程基础知识(一)

    一. 基础知识 要了解多线程首先要知道一些必要的概念,如进程,线程等等.开发多线程的程序有利于充分的利用系统资源(CPU资源),使你的程序执行的更快,响应更及时. 1. 进程,一般是指程序或者任务的执 ...

  7. Java多线程基础知识总结笔记

    本篇笔记记录一些在Java多线程编程中常见的关键字,比较简单和基础的就不写太详细了. 一.Thread类(其实也是应用了Runnable接口)和Runnable接口(只有一个run方法,应用该类必须重 ...

  8. Java多线程基础知识例子

    一.管理 1.创建线程 Thread public class Main { public static void main(String[] args) { MyThread myThread = ...

  9. Java多线程基础知识(二)

    一. Java线程具有6种状态  NEW 初始状态,线程被创建,但是还没有调用start方法. RUNNABLE 运行状态,java线程将操作系统中的就绪和运行两种状态笼统的称作进行中. BLOCKE ...

随机推荐

  1. 关于vs生成app错误提示,提醒Execution failed for task ':transformClassesWithDexForDebug'.

    昨天将vs和android SDK更新之后生成app之后发现app生成出错,报错如下: FAILURE: Build failed with an exception. * What went wro ...

  2. js005-引用类型

    js005-引用类型 数据类型分为基本类型和引用类型:基本类型值如下:Undefined.Null.Bollean.Number.String 本章内容: 1.使用对象 2.创建并操作数组 3.理解基 ...

  3. WinForm------GridControl的部分属性介绍

    参考其它链接: http://www.cnblogs.com/djian/archive/2010/11/19/1881579.html //注意:在定义GridControl里面的FileName里 ...

  4. JavaWeb学习笔记——JavaEE基础知识

  5. rem自适应布局的回顾总结

    使用rem实现自适应布局,应该算是当前移动前端的一大趋势,有些人对此还有点迷惑,搞不懂rem是如何实现自适应布局,如何根据设计稿来调整rem的值?rem布局如何用雪碧背景图片?rem一定要加载JS吗? ...

  6. RGB to HSI, HSI to RGB Conversion Calculator

    The RGB color model is an additive system in which each color is defined by the amount of red, green ...

  7. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+pat----------<base>元素有关

    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request. ...

  8. centos 7.0 菜鸟接触命令 记录

    centos 7.0 最小化安装 查看IP ip addr 查看外网IP curl ifconfig.me 重启 shutdown -r now 安装wget yum -y install wget ...

  9. HBase中的压缩算法比较 GZIP、LZO、Zippy、Snappy [转]

    网址: http://www.cnblogs.com/panfeng412/archive/2012/12/24/applications-scenario-summary-of-compressio ...

  10. php.ini中有关安全的设置

    php的默认配置文件在 /usr/local/apache2/conf/php.ini,通过为了使你的web更安全,我们需要对php.ini进行一些设置! (1) 打开php的安全模式 php的安全模 ...