面试之Java线程池--手写自己的线程池

背景:2019年4月春招找实习,面试华为后端开发,面试官上来给了一张A4纸,让手写一个java线程池,要求可运行。
使用ExecutorService框架胡乱写了一点线程池的东西,但明显是不足以运行起来的。最后也以至于面试挂掉了。。秋招已经开始了,所以自己查看资料弄清楚了线程池的原理之后,编写了一个自己的线程池,记录一下。

============================ 分割线 ================================

一、首先回顾一下线程池的原理

线程池处理一个任务分三个阶段,具体如下图:

面试之Java线程池--手写自己的线程池_第1张图片

根据以上流程图,编写线程池代码

1.线程池类
package scu.stone.thread;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class MyThreadPool {
	//线程池中默认线程的个数为5
	private static int WORK_NUM = 5;
	//队列默认任务为100
	private static int TASK_COUNT = 100;
	
	//工作线程数组
	private WorkThread[] workThreads;
	//等待队列
	private final BlockingQueue<Runnable> taskQueue;
	//用户在构造这个线程池时,希望启动的线程数
	private final int workerNum;  
	
	/**
	 * 内部类,工作线程类
	 */
	private class WorkThread extends Thread{
		@Override
		public void run() {
			Runnable runnable = null;
			try {
				while (! isInterrupted()) {  //如果没有被标记中断,则从对阻塞队列中取出任务执行
					runnable = taskQueue.take();  //take:阻塞接口的移除方法
					if (runnable != null) {
						System.out.println("Thread ID:" + getId() + " ready exec:" + runnable.toString());
						runnable.run();
					}
					runnable = null;  //help gc 
				}
			} catch (Exception e) {
				// TODO: handle exception
			}
		}
		//线程停止工作
		public void stopWork() {
			interrupt();
		}
	}
	
	//构造方法:创建具有默认线程个数的线程池
	public MyThreadPool() {
		this(WORK_NUM,TASK_COUNT);
	}

	//创建线程池,workNum为线程池中工作线程的个数
	public MyThreadPool(int workerNum, int taskCount) {
		if (workerNum <= 0) {
			workerNum = WORK_NUM;
		}
		if (taskCount <= 0) {
			taskCount = TASK_COUNT;
		}
		this.workerNum = workerNum;
		taskQueue = new ArrayBlockingQueue<>(taskCount);
		workThreads = new WorkThread[workerNum];
		for (int i = 0; i < workerNum; i++) {
			workThreads[i] = new WorkThread();  //new一个工作线程
			workThreads[i].start();  //启动工作线程
		}
		Runtime.getRuntime().availableProcessors();
	}
	//执行任务,其实就是把任务加入任务队列,什么时候执行由线程池管理器决定
	public void execute(Runnable task) {
		try {
			taskQueue.put(task);   //put:阻塞接口的插入
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
	//销毁线程池,该方法保证所有任务都完成的情况下才销毁所有线程,否则等待任务完成再销毁
	public void destory() {
		//工作线程停止工作,且置为null
		System.out.println("ready close thread...");
		for (int i = 0; i < workerNum; i++) {
			workThreads[i].stopWork();
			workThreads[i] = null; //help gc
		}
		taskQueue.clear();  //清空等待队列
		
	}
	//覆盖toString方法,返回线程信息:工作线程个数和已完成任务个数
	@Override
	public String toString() {
		return "WorkThread number:" + workerNum + " ==分割线== wait task number:" + taskQueue.size();
	}
}

2.任务类

package scu.stone.thread;

import java.util.Random;

public class MyTask implements Runnable {
	
	private String name;
	public String getName() {
		return name;
	}

	private Random random = new Random();
	
	public MyTask(String name) {
		this.name = name;
	}

	@Override
	public void run() {
		try {
			Thread.sleep(random.nextInt(1000) + 2000);
		} catch (Exception e) {
			System.out.println(Thread.currentThread().getId() + "sleep InterruptedException:" + 
					Thread.currentThread().isInterrupted());
		}
		System.out.println("task--- " + name + "---done!");
	}
}

3.测试类

package scu.stone.thread;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestMyThreadPool extends ThreadPoolExecutor{
	public TestMyThreadPool(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
			BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler) {
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
	}
	
	public static void main(String[] args) throws InterruptedException {
		//创建3个线程的线程池
		MyThreadPool myThreadPool = new MyThreadPool(3, 3);
		myThreadPool.execute(new MyTask("A"));
		myThreadPool.execute(new MyTask("B"));
		myThreadPool.execute(new MyTask("C"));
		myThreadPool.execute(new MyTask("D"));
		myThreadPool.execute(new MyTask("E"));
		
		System.out.println(myThreadPool);
		Thread.sleep(10000);
		myThreadPool.destory(); //所有线程都执行完成后,再destory
		System.out.println(myThreadPool);
	}
}

4.测试结果,如下:
面试之Java线程池--手写自己的线程池_第2张图片

你可能感兴趣的:(java,线程)