线程池
什么线程池?为什么使用线程池 1.降低线程创建和销毁的资源消耗 2.提高响应的速度 一个线程整个生命周期分三个时间段:T1创建时间,T2执行时间,T3销毁时间。如果使用一般模式创建线程,那么消耗是T1+T2+T3时间总和,如果采用线程池可以避免T1和T3这时间。 3.提高线程的管理性
实现一个线程池
1.线程必须在线程池中已经创建好了,并且可以保持性,要有容器可以保存多个线程 2.线程还能接受外部的任务,运行这个任务 实现思路:初始化对象时候,创建指定线程数量,让每次调用该对象的execute方法,将线程加入队列中等待去执行
package ms.studyjava.threads.demo9;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class MyThreadPool {
private final static int WORK_NUM = 5;
private final static int TASK_COUNT = 10;
private WorkThread[] workThreads;
private BlockingQueue<Runnable> taskQueue;
private int workNum;
public MyThreadPool() {
this(WORK_NUM, TASK_COUNT);
}
public MyThreadPool(int workNum, int taskCount) {
this.workNum = workNum <= 0 ? WORK_NUM : workNum;
this.taskQueue = new ArrayBlockingQueue<Runnable>(taskCount <= 0 ? TASK_COUNT : taskCount);
workThreads = new WorkThread[workNum];
for (int i = 0; i < workNum; i++) {
workThreads[i] = new WorkThread();
workThreads[i].start();
}
}
public void execute(Runnable task) {
try {
taskQueue.put(task);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void destory() {
System.out.println("线程池销毁中...");
for (int i = 0; i < workThreads.length; i++) {
workThreads[i].stopWork();
workThreads[i] = null;
}
taskQueue.clear();
}
class WorkThread extends Thread {
@Override
public void run() {
Runnable r = null;
try {
while (!isInterrupted()) {
r = taskQueue.take();
if (r != null) {
r.run();
System.out.println(Thread.currentThread().getName() + "准备执行中.....");
}
r = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void stopWork() {
isInterrupted();
}
}
}
public class TestDemo9 {
public Runnable creatRunnable(String name) {
return new Runnable() {
@Override
public void run() {
System.out.println(name + "提交给线程池中....");
}
};
}
public static void main(String[] args) {
TestDemo9 testDemo9 = new TestDemo9();
MyThreadPool myThreadPool = new MyThreadPool(3, 1);
myThreadPool.execute(testDemo9.creatRunnable("A"));
myThreadPool.execute(testDemo9.creatRunnable("B"));
myThreadPool.execute(testDemo9.creatRunnable("C"));
myThreadPool.execute(testDemo9.creatRunnable("D"));
myThreadPool.execute(testDemo9.creatRunnable("E"));
myThreadPool.execute(testDemo9.creatRunnable("F"));
myThreadPool.execute(testDemo9.creatRunnable("G"));
myThreadPool.execute(testDemo9.creatRunnable("H"));
SleepTools.sencod(3);
myThreadPool.destory();
System.out.println(myThreadPool);
}
}
以上自己实现线程池的缺点: 1.任务不可取消,没有超时机制 2.上面自己实现的初始化时候,就已经把数量规定死了,无法调整数量 3.当线程突然暴增无法处理,会阻塞在队列中,造成调用者响应速度下降
JDK的线程池
各个参数的意义
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
corePoolSize 线程池中的核心线程数,当<corePoolSize就会创建新的线程,>corePoolSizesh时候会将新的线程加入到队列中。 maximumPoolSize 允许的最大线程数,当队列也满了,<maximumPoolSize会再次创建新的线程。数量等于了maximumPoolSize,就用RejectedExecutionHandler来执行拒绝策略 keepAliveTime:线程空闲下来的时候,存活的时间,只有在线程数大于corePoolSizesh时候才有用 unit 线程存活的时间单位 workQueue 保存任务的阻塞队列 threadFactory 创建线程的工厂,给新建的线程赋予名字 handler 饱和策略。由于达到线程边界和队列容量而阻塞执行时使用的处理程序 四种策略模式 1.AbortPolicy:直接抛出异常,默认的 2.CallerRunsPolicy:用调用者所在的线程来执行任务 3.DiscardOldestPolicy:丢弃阻塞队列里最老的任务,队列里最靠前的任务 4:DiscardPolicy:当前任务直接丢弃
工作机制
提交任务
execute(Runnable command)不带返回值的线程池 submit(Callable task)提交带有返回值的线程. 提交任务四步总结 1.如果当前线程数量小于核心线程数量,那么会创建新的线程 2.如果当前线程数量大于等于核心线程数量时候并且小于最大线程数量,会将提交的任务加入到队列中。 3.如果队列满了,并且小于最大线程数量时候,会创建新的线程 4.如果线程数大于最大线程数量,会调用拒绝策略,默认的是抛出异常
线程池提交带有返回值
public static void main(String[] args) throws ExecutionException, InterruptedException {
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(6);
ThreadPoolExecutor pools = new ThreadPoolExecutor(5, 10, 320, TimeUnit.MILLISECONDS, queue);
List<Future<String>> futureList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
int finalI = i;
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
return "i的值=" + finalI;
}
};
Future<String> future = pools.submit(callable);
futureList.add(future);
}
System.out.println("准备打印返回值....");
SleepTools.sencod(3);
for (Future<String> futureTask : futureList) {
System.out.println(futureTask.get());
}
}
关闭线程池
shutdown:设置线程池状态,只会中断所有没有执行任务的线程 shutdownNow:设置线程池的状态,还会尝试停止正在运行的或者暂停任务的线程
execute源码分析
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
合理配置线程池
推荐线程池使用使用有界队列
预定义的线程池
ScheduledThreadPoolExecutor
Excutor框架
|