[改善Java代码]优先选择线程池
在Java1.5之前,实现多线程编程比较麻烦,需要自己启动线程,并关注同步资源,防止线程死锁等问题,在1.5版本之后引入了并行计算框架,大大简化了多线程开发.
我们知道线程有5个状态:新建状态(New),可运行状态(Runnable,也叫做运行状态),阻塞状态(Blocked),等待状态(Waiting),结束状态(Terminated),线程的状态只能由新建状态转变为运行状态后才可能被阻塞或者等待,最终终结.
不可能出现本末倒置的情况,比如想把一个结束状态的线程转变为新建状态,则会出现异常.例如下面代码会出现异常:
import java.util.concurrent.TimeUnit; public class Client {
public static void main(String[] args) throws Exception {
// 创建一个线程,新建状态
Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("线程在运行……");
}
});
// 运行状态
t.start();
// 是否是运行态,若不是则等待10毫秒
while (!t.getState().equals(Thread.State.TERMINATED)) {
TimeUnit.MILLISECONDS.sleep(10);
}
System.out.println(t.getState());//TERMINATED
// 直接由结束态转变为运行态
t.start();
}
}
会报如下错误:
线程在运行……
TERMINATED
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Unknown Source)
at cn.summerchill.test.Client.main(Client.java:20)
出现上面的异常就是不能从结束状态直接转变成可运行状态.
一个线程的运行时间分为三部分:T1为线程的启动时间,T2为线程的运行时间,T3为线程的销毁时间.如果一个线程不能被重复使用,每次创建一个线程都需要经过启动,运行,销毁这三个过程,那么这势必会增大系统的响应时间,有没有一个更好的方法降低线程的运行时间?
T2是无法避免的,只有通过代码优化缩短线程的运行时间.
T1和T2都可以通过线程池ThreadPool来缩短时间,比如在容器或者系统启动时,创建足够多的线程,当容器或系统需要时直接从线程池中获取,运算出结果再把线程返回到线程池中---ExecutorService就是实现了线程池的执行器,看实例代码:
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor; public class Client {
public static void main(String[] args) {
//2个线程的线程池
ThreadPoolExecutor es = (ThreadPoolExecutor)Executors.newFixedThreadPool(2);
//多次执行线程体
for (int i = 0; i < 4; i++) { es.submit(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
System.out.println(es.getPoolSize());
System.out.println(es.getCorePoolSize());
//关闭执行器
es.shutdown();
}
}
运行结果:
pool-1-thread-1
pool-1-thread-2
pool-1-thread-2
2
2
pool-1-thread-1
本次代码执行了4遍线程体,按照我们之前说的:一个线程不可能从结束状态转变为可运行状态,那为什么此处的2个线程可以反复使用呢?这就是我们要搞清楚的重点:
线程池的实现涉及以下三个名词:
(1)工作线程(Worker)
线程池中的线程,只有两个状态:可运行状态和等待状态,在没有任务的时候就处于等待状态,运行时可以循环的执行任务.
(2)任务接口(Task)
这是每个任务必须实现的接口,以供工作线程调度器调度,它主要规定了任务的入口,任务执行完的场景处理,任务的执行状态等...
这里有两种类型的任务,具有返回值或异常的Callable接口任务和无返回值并兼容旧版本的Runnable接口任务.
(3)任务队列(Work Queue)
用于存放等待处理的任务,一般是BlockingQueue的实现类,用来实现任务的排队处理.
***********分析源码****************
线程池的创建过程:
创建一个阻塞队列以容纳任务,在第一次执行任务时创建足够多的线程(不可超过许可线程数),并处理任务.之后每个工作线程自行从任务队列中获得任务,直到任务队列中的任务数量为0为止.
此时线程处于等待状态,一旦有任务再加入到队列中,即唤醒工作线程进行处理,实现线程的可复用性.
使用线程池减少的是线程的创建和销毁时间,这对于多线程来说非常有帮助.
我们常用的Servlet容器,每次请求处理的都是一个线程,如果不采用线程池技术,每次请求都会重新创建一个线程,这会导致系统的性能负荷加大,响应效率下降,降低了系统的友好性.
[改善Java代码]优先选择线程池的更多相关文章
- [改善Java代码]适时选择不同的线程池来实现
Java的线程池实现从最根本上来说只有两个:ThreadPoolExecutor类和ScheduledThreadPoolExecutor类,这两个类还是父子关系,但是Java为了简化并行计算,还提供 ...
- [改善Java代码]优先使用整型池
建议28: 优先使用整型池 看如下代码: public class Client { public static void main(String[] args) { Scanner input = ...
- [改善Java代码]适时选择getDeclaredxxx和getxxx
Java的Class类提供了很多的getDeclaredxxx方法和getxxx方法,例如getDeclaredmethod和getMethod成对出现,getDeclaredConstructors ...
- [改善Java代码]自由选择字符串拼接方法
对一个字符串拼接有三种方法:加号,contact方法,StringBuffer或者StringBuilder的append方法,其中加号是最常用的.其他两种方式偶尔会出现在一些开源项目中,那么这三者有 ...
- Java并发编程:线程池的使用
Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...
- JAVA基础拾遗-论线程池的线程粒度划分与深浅放置
摘要:多线程任务处理对提高性能很有帮助,在Java中提供的线程池也方便了对多线程任务的实现.使用它很简单,而如果进行了不正确的使用,那么代码将陷入一团乱麻.因此如何正确地使用它,如以下分享,这个技能你 ...
- Java并发编程:线程池的使用(转)
Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...
- 深入理解Java自带的线程池和缓冲队列
前言 线程池是什么 线程池的概念是初始化线程池时在池中创建空闲的线程,一但有工作任务,可直接使用线程池中的线程进行执行工作任务,任务执行完成后又返回线程池中成为空闲线程.使用线程池可以减少线程的创建和 ...
- Java并发编程:线程池的使用(转载)
转载自:https://www.cnblogs.com/dolphin0520/p/3932921.html Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实 ...
随机推荐
- 现代程序设计——homework-07
1.写在前面 不得不很惭愧地说,在看这些博客之前,我对C++的了解仅限于上过一门特别水的关于C++的公选课.一门只有五节课的专业选修课,写过一点点符合C++语法语法规则的类C程序,偶尔在论坛.博客中看 ...
- 【转】你真的了解iOS代理设计模式吗?
转自:http://www.cocoachina.com/ios/20160317/15696.html 在项目中我们经常会用到代理的设计模式,这是iOS中一种消息传递的方式,也可以通过这种方式来传递 ...
- UVALive 7324 ASCII Addition (模拟)
ASCII Addition 题目链接: http://acm.hust.edu.cn/vjudge/contest/127407#problem/A Description Nowadays, th ...
- codeforces Ebony and Ivory(水题)
A. Ebony and Ivory time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- Windows-to-go-带着win10满街跑
一.前言 有句话是这么说的,程序员对工作是时刻准备着的.无论你是长假还是短假,只要有网,你就躲不开客户.这样子,当你外出的时候你可以选择时刻背着电脑,因为你的电脑有着你顺手的开发工具以及开发环境.我们 ...
- CPU与内存(经典问答)
原文:http://www.cnblogs.com/xkfz007/archive/2012/10/08/2715163.html 下面是网上看到的一些关于内存和CPU方面的一些很不错的文章. 整理如 ...
- Oracle RMAN 清除归档日志
在开发环境及UAT环境经常碰到需要清除归档日志的情形,对于这个问题方法有很多.可以直接使用rm方式清除归档日志,也可以使用find命令来查找符合条件的记录来清除归档日志,或者直接写个shell脚本来搞 ...
- Codeforces Bubble Cup 8 - Finals [Online Mirror] D. Tablecity 数学题
D. Tablecity Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/575/problem/D ...
- Codeforces Gym 100418B 暴力
Sum of sequencesTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/v ...
- c#加密 可逆与不可逆MD5 加密
1.方法一 (不可逆加密) srxljl public string EncryptPassword(string PasswordString,string PasswordFormat ) ...