线程池建立线程的方式必定效率高吗?

java多线程的效率就必定高吗?html

 

import java.util.LinkedList;java

public class ThreadPool extends ThreadGroup {缓存

private boolean isClosed = false; // 线程池是否关闭
private LinkedList workQueue; // 工做队列
private static int threadPoolID = 1; // 线程池的id多线程

public ThreadPool(int poolSize) {
super(threadPoolID + "");// 指定ThreadGroup的名称
setDaemon(true); // 继承到的方法,设置是否守护线程池
workQueue = new LinkedList(); // 建立工做队列
for (int i = 0; i < poolSize; i++) {
new WorkThread(i).start(); // 建立并启动工做线程,线程池数量是多少就建立多少个工做线程
}并发

}异步

/** 等待工做线程把全部任务执行完毕 */
public void waitFinish() {
synchronized (this) {
isClosed = true;
notifyAll(); // 唤醒全部还在getTask()方法中等待任务的工做线程
}
// activeCount() 返回该线程组中活动线程的估计值。
Thread[] threads = new Thread[activeCount()];
// enumerate()方法继承自ThreadGroup类,根据活动线程的估计值得到线程组中当前全部活动的工做线程
int count = enumerate(threads);
for (int i = 0; i < count; i++) { // 等待全部工做线程结束
try {
threads[i].join(); // 等待工做线程结束
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}性能

/** 关闭线程池 */
public synchronized void closePool() {
if (!isClosed) {
// 等待工做线程执行完毕
waitFinish();
isClosed = true;
// 清空工做队列
workQueue.clear();
// 中断线程池中的全部的工做线程,此方法继承自ThreadGroup类
interrupt();
}
}测试

/** 向工做队列中加入一个新任务,由工做线程去执行该任务 */
public synchronized void execute(Runnable task) {
if (isClosed) {
throw new IllegalStateException();
}
if (task != null) {
// 向队列中加入一个任务
workQueue.add(task);
// 唤醒一个正在getTask()方法中待任务的工做线程
notify();
}
}this

/** 从工做队列中取出一个任务,工做线程会调用此方法 */
private synchronized Runnable getTask(int threadid)
throws InterruptedException {
while (workQueue.size() == 0) {
if (isClosed) {
return null;
}
System.out.println("工做线程" + threadid + "等待任务...");
wait(); // 若是工做队列中没有任务,就等待任务
}
System.out.println("工做线程" + threadid + "开始执行任务...当前任务数:"
+ workQueue.size());
// 反回队列中第一个元素,并从队列中删除
return (Runnable) workQueue.removeFirst();
}spa

/**
* 内部类,工做线程,负责从工做队列中取出任务,并执行
*
* @author sunnylocus
*/
private class WorkThread extends Thread {
private int id;

public WorkThread(int id) {
// 父类构造方法,将线程加入到当前ThreadPool线程组中
super(ThreadPool.this, id + "");
this.id = id;
}

public void run() {
while (!isInterrupted()) { // isInterrupted()方法继承自Thread类,判断线程是否被中断
Runnable task = null;
try {
task = getTask(id); // 取出任务
} catch (InterruptedException ex) {
ex.printStackTrace();
}
// 若是getTask()返回null或者线程执行getTask()时被中断,则结束此线程
if (task == null)
return;

try {
takeTimeOperation();
// this.sleep(5000);
task.run(); // 运行任务
} catch (Throwable t) {
t.printStackTrace();
}
}// end while
}// end run
}// end workThread

// 耗时的操做,乱写了一个
private void takeTimeOperation() {
int i = 0;
String test = "";
while (i < ThreadPoolTest.TAKETIME_NUM) {
test += "" + i;
i++;
}
}

}


---------------------
测试类:


public class ThreadPoolTest {

//线程数
private static final int THREAD_NUM = 2;

//任务数
private static final int TASK_NUM=15;

//费时的操做的时间度
public static final int TAKETIME_NUM=5500;

public static void main(String[] args) throws InterruptedException {
long beginTime = System.currentTimeMillis();
// 建立一个有THREAD_NUM个工做线程的线程池
ThreadPool threadPool = new ThreadPool(THREAD_NUM);
// 休眠500毫秒,以便让线程池中的工做线程所有运行
Thread.sleep(500);
// 运行任务
for (int i = 0; i <= TASK_NUM; i++) { // 建立TASK_NUM个任务
threadPool.execute(createTask(i));
}
threadPool.waitFinish(); // 等待全部任务执行完毕
threadPool.closePool(); // 关闭线程池
long endTime = System.currentTimeMillis();
System.out.print("****当前线程数:" +THREAD_NUM+ ",******共用时间:" + (endTime - beginTime));

}

private static Runnable createTask(final int taskID) {
return new Runnable() {
public void run() {
// System.out.println("Task" + taskID + "开始");
System.out.println("Hello world");
// System.out.println("Task" + taskID + "结束");
}
};
}

}

 

一、若是线程操做的是耗时,可是不耗cpu的操做时,就是ThreadPool的WorkThread中将takeTimeOperation();这行注释掉,将this.sleep(5000);开放,一样用16个任务数测试的结果能够发现,线程数的提升对系统的性能的改进是很明显的。在线程数等于任务数的时候达到最高,若是线程数高于任务数就没什么意义了。

 

二、若是线程操做耗时,又耗cpu的状况,就是ThreadPool的WorkThread中将takeTimeOperation();这行开放,将this.sleep(5000);注释掉。一样用16个任务数测试的结果能够发现线程数的提升,系统的性能反而降低了,在线程数为2的时候性能最好,估计是个人cpu是双核的缘由。当线程为1的时候对cpu的利用率不高,线程过大时cpu由于自身的压力已经达到瓶颈了因此此时很难提升性能,虽然提升了并发,但你们的处理速度估计都慢下来了。并且线程自己也是要开销的,固然反正用的是池技术也就是第一次建立的时候会慢一点,接下来都从池里面取的话,对性能开销是微乎其微的。不过线程是占内存的,若是线程池开太大的话有内存溢出的危险。

 

三、注意:CountDownLatch异步转同步的时候,会在全部的服务中new Thread,这样作是最保险的?若是用线程池来作:固定大小线程池有可能并发数大的时候线程已用完而致使等待超时(等待超时的问题能够将线程池的线程数设置为一次任务所须要的线程数的整数倍,多少倍也就决定了并发数,这样作很差的地方也就是线程池数设置小了没法最大化利用硬件资源,线程池设置大了会在并发量小的时候浪费硬件资源)。无限线程池Executors.newCachedThreadPool()有可能致使内存所有消耗殆尽(虽然已作串化处理,但仍是没法知足使用的前提:耗时较短的任务,且任务处理速度 > 任务提交速度,若是一直不回收线程建立的资源,内存会很快消耗完毕)。结论:并发执行的效率不必定比串行执行高,由于多线程在执行的时候会有个抢占CPU资源,上下文切换的过程。详细见线程的生命周期!

思考

一、串行执行方式对每次请求的处理须要的硬件资源是差很少的,不会出现过量消耗系统资源,那也就能够在CountDownLatch的时候使用Executors.newCachedThreadPool()来池化线程,由于第一次请求结束第二次请求来的时候,仍是一样的业务逻辑。且缓存线程池中的线程空闲后只会保留60秒,而固定长度线程池中的线程会一直保留,因此反而不适用。

二、注意缓存线程池的使用前提,对于长时间耗时耗CPU的计算并不适合,反而直接new Thread更加适合,详见:为何要使用线程池线程池的意义和生命周期

三、缓存线程池使用场景能够用于如:request请求进入后insert流水,解析请求报文,插入串行队列。这样作能够当即返回response。

相关文章
相关标签/搜索