很久没上来了,发现虽然资料和书看的很多,但是很久没碰的东西还是很容易淡忘。以后希望能多记录吧。
今天玩了把线程池,并对其中的参数做了一些调整,并记录在多并发情况下线程数对各种情况的反应。程序是网上找的,并作了稍微修改。
java的线程池实现,ThreadPool
package net.zj.hz.yk.threadpool; import java.util.LinkedList; 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(); } } /** 从工作队列中取出一个任务,工作线程会调用此方法 */ 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(); } /** * 内部类,工作线程,负责从工作队列中取出任务,并执行 * * @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++; } } }
测试类:
package net.zj.hz.yk.threadpool; 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 + "结束"); } }; } }
1.如果线程操作的是耗时,但是不耗cpu的操作时,就是ThreadPool的WorkThread中将takeTimeOperation();这行注释掉,将this.sleep(5000);开放,同样用16个任务数测试的结果如下
****当前线程数:3,******共用时间:30516
****当前线程数:6,******共用时间:15516
****当前线程数:12,******共用时间:10516
****当前线程数:24,******共用时间:5500
****当前线程数:16,******共用时间:5500
可以发现,线程数的提高对系统的性能的改进是很明显的。在线程数等于任务数的时候达到最高,如果线程数高于任务数就没什么意义了。
2.如果线程操作耗时,又耗cpu的情况,就是ThreadPool的WorkThread中将takeTimeOperation();这行开放,将this.sleep(5000);注释掉。同样用16个任务数测试的结果如下
****当前线程数:1,******共用时间:4344
****当前线程数:2,******共用时间:3828
****当前线程数:3,******共用时间:4297
****当前线程数:6,******共用时间:4453
****当前线程数:12,******共用时间:4875
****当前线程数:16,******共用时间:5062
可以发现线程数的提高,系统的性能反而下降了,在线程数为2的时候性能最好,估计是我的cpu是双核的原因。当线程为1的时候对cpu的利用率不高,线程过大时cpu因为自身的压力已经达到瓶颈了所以此时很难提高性能,虽然提高了并发,但大家的处理速度估计都慢下来了。而且线程本身也是要开销的,当然反正用的是池技术也就是第一次创建的时候会慢一点,接下来都从池里面取的话,对性能开销是微乎其微的。不过线程是占内存的,如果线程池开太大的话有内存溢出的危险。