java并发的艺术-读书笔记-第九章线程池

使用线程池的好处:

1.降低资源消耗:减少了线程创建和销毁的资源消耗

2.提高响应速度,当任务到达时,线程可以不尽兴创建直接处理

3.提高线程的可管理性。使用线程池可以对线程进行统一的管理,监控,使用。

线程池的源码分析:

public void execute(Runnable command){

if(command==null){

throw new NullPointerException();

}

//如果执行线程数小于基本线程,则创建线程,并执行任务

if(poolsize>=corepoolsize||!addifundercoresize(command)){

//如果线程池数量大于等于核心池数量或者线程创建失败,直接放入队列中

if(runstate==runnable&&workQueue.offer(command)){

if(runstate!=runnable||poolsize==0){

eusureQueueTaskHandled(command);

}

}

//如果线程池不处于运行中或者无法放入任务队列,并且当前线程小于最大允许线程,则创建新线程

if(!addundermaxpoolsize(command)){

reject(command);

}

}

}

工作线程伪代码如下:

public void runnable(){

Runnable task=firsttask;

firsttask=null;

while(task!=null||task=workQueue.get()!=null){

runtask(task);

task=null;

}

finally{

workDone(this);

}

}

线程池的使用

创建线程池:new ThreadPoolExecutor(corepoolsize,maxpoolsize,keepalivetime,millseconds,runnabletaskqueue,hander);

参数说明

runnabletaskqueue,是一个用于存储任务的阻塞队列,通常 arryayblockingqueue linkedblockingqueue pritoryblockingqueue

hander:饱和策略:1 abortpolicy  丢弃  2 discardpolicy  不丢弃 3 callerrunspolicy 只有调用者线程来执行,discardoldestpolicy 丢弃队列里最近的一个任务,并执行当前任务

keepalivetime:线程池中的工作线程空闲后,可以保持存活的有效时间

timeunit:可保持存活时间的 有效单位 天 ,小时 分,秒等

向线程池中提交任务:execute 和submit

execute 用于提交无返回值的结果

submit用于提交有返回值的线程

通过submit方法提交的线程会返回一个future类型的对象,通过这个future类对象可以判断返回值时否成功。通过future。get方法获取返回值,get方法会阻塞当前线程,直到任务完成,并且get方法可以设置时间来实现异步调用返回

关闭线程池

关闭线程池游两种方法:shutdown shutdownNow方法关闭线程池

shutdown原理:逐个遍历工作线程,调用工作线程的interrupt方法,所以无法中断响应的线程可能无法终止。

shutdownnow原理:首先将线程池设置成stop状态,然后尝试终止所有正在执行或暂停任务的线程,并返回等待执行的任务列表。只要调用了两种方法中的任意一种,则isshutdown返回true,当所有任务已关闭,才表示线程池关闭成功则isterminaled返回true,shutdownnow方法可能任务不一定会执行完。通常使用shutdown来关闭

合理配置线程池

cpu密集型任务应配置尽可能小的线程。如配置cup+1个线程。由于io密集型任务并不一定是在一直执行任务。所以应配置尽可能多的线程,如配置2*cup个线程。如果是混合型的任务则可以拆分。拆分成一个cup密集型的任务和一个io密集型的任务,如果这两个任务执行时间相差不大则吞吐量高于单线程任务,如果相差太大则没必要进行分解。

Runtime.getRuntime.getAvaliableProcessors 获得cup数量

优先级不同的任务可使用优先级队列pritorityblockqueue来处理

建议使用有界队列,因为出现异常任务积压时可以执行拒绝策略,及时预警

线程池的监控

taskcount :线程池中需要执行的任务数量

completaskcount:线程池已经完成的线程数量

largestpoolsize:线程池中曾经创建过的最大的线程数量

poolsize 线程池中的线程数量

getactivecount:线程池中活动的线程树

可以通过继承线程你来自定义线程池的 beforeExecute afterExecute terminated 方法来对线程池进行监控

时间: 2024-08-03 07:20:48

java并发的艺术-读书笔记-第九章线程池的相关文章

《Java并发变成实践》读书笔记---第二章 线程安全性

什么是线程安全性 要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的(Shared)和可变的(Mutable)状态的访问.从非正式的意义上来说,对象的状态是指存储在状态变量(例如实例或静态域)中的数据."共享"意味着变量可以由多个线程同时访问,而"可变"则意味着变量的值在其生命周期内可以发生变化.所以编写线程安全的代码更侧重于如何防止在数据上发生不受控的并发访问. 如果当多个线程访问同一个可变的状态变量时没有使用合适的同步,那么程序就会出现错误

JAVA并发编程实战 读书笔记(二)对象的共享

<java并发编程实战>读书摘要 birdhack 2015年1月2日 对象的共享 JAVA并发编程实战读书笔记 我们已经知道了同步代码块和同步方法可以确保以原子的方式执行操作,但一种常见的误解是,认为关键之synchronized只能用于实现原子性或者确定临界区.同步还有另一个重要的方面:内存可见性. 1.可见性 为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制. 在没有同步的情况下,编译器.处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整.在缺乏足够同步的多线程程

读书笔记第九章

第九章HAL是建立在linux驱动之上的一套程序库.这套程序库并不属于linux内核,而是属于linux内核层之上的应用层.可以用来保护不想公开源代码的作者.HAL架构比较简单,其基本原理就是在安卓系统中使用程序库调用位于内核空间的linux驱动,然后安卓应用程序可以通过NDK程序访问HAL中的程序库,或直接在安卓应用程序中访问HAL中的程序库.编写一款支持HAL的linux驱动程序的步骤:1.编写linux驱动,linux驱动的代码要尽量简介,尽可能将业务逻辑放到HAL library中.2.

Java并发编程实践(读书笔记) 任务执行(未完)

任务的定义 大多数并发程序都是围绕任务进行管理的.任务就是抽象和离散的工作单元.   任务的执行策略 1.顺序的执行任务 这种策略的特点是一般只有按顺序处理到来的任务.一次只能处理一个任务,后来其它任务都要等待处理.响应性很糟糕,吞吐量低.系统资源利用率低. 2.显示的为任务创建线程 为每个任务创建对应一个线程,响应快,系统资源利用路高.缺点是资源消耗量大,如果有大量任务要执行的话,系统迟早会因为无限制创建过多的线程而造成内存耗尽.特别当创建的线程数量远远大于系统的CPU核数,由于每一个核同一时

Java并发编程实践读书笔记(5) 线程池的使用

Executor与Task的耦合性 1,除非线程池很非常大,否则一个Task不要依赖同一个线程服务中的另外一个Task,因为这样容易造成死锁: 2,线程的执行是并行的,所以在设计Task的时候要考虑到线程安全问题.如果你认为只会在单任务线程的Executor中运行的话,从设计上讲这就已经耦合了. 3,长时间的任务有可能会影响到其他任务的执行效率,可以让其他线程在等待的时候限定一下等待时间.不要无限制地等待下去. 确定线程池的大小 给出如下定义: 要使CPU达到期望的使用率,线程池的大小应设置为:

[Java并发编程之美]第1章 线程基础(待更新)

第1章 线程 线程与进程 进程是操作系统资源分配和调度的基本单位,但cpu资源是分配到线程的,也就是线程是CPU分配的基本单位. 线程自己的栈资源中,存放的局部变量是线程私有的,其他线程无法访问,除此之外栈还存线程的调用栈帧. 线程创建 三种方式:实现Runnable接口的run方法:继承Thread类并重写run方法:使用FutureTask方式. 线程等待与通知 1 wait() 线程先要事先获得共享变量上的监视器锁,然后当一个线程调用一个共享变量的wait()方法,该线程会被阻塞挂起,并且

Java并发编程(十二):线程池的使用(转载)

本文转载自:http://www.cnblogs.com/dolphin0520/p/3932921.html 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务? 在Java中可以通过线程池来达到这样的效果.

Java并发编程实践读书笔记--第一部分 基础知识

目前关于线程安全性没有一个统一的定义,作者自己总结了一个定义,如下:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么就称这个类是线程安全的. 在并发编程中,由于不恰当的执行时序而出现不确定的结果的情况被称为竞态条件(Race Condition).最常见的竞态条件就是“先检查后执行(Check-Then-Act)”操作,即通过一个可能已经失效的观察来决定下一步的动作.比较简单的例子就是两

Redis Essentials 读书笔记 - 第九章: Redis Cluster and Redis Sentinel (Collective Intelligence)

Chapter 9. Redis Cluster and Redis Sentinel (Collective Intelligence) 上一章介绍了复制,一个master可以对应一个或多个slave(replica), 在以下的情况下是够用的: 1. master有足够内存容纳所有key 2. 通过slave可以扩展读,解决网络吞吐量的问题 3. 允许停止master的维护窗口时间 4. 通过slave做数据冗余 但复制解决不了自动failover和自动resharding的问题,在以下的情