自定义线程池队列的选择
- 使用有界队列(ArrayBlockingQueue)自定义线程池,当任务的数量小于corePoolSize的时候,直接创建新的线程执行任务。当任务数量大于corePoolSize的时候会将任务加入到等待队列。若等待队列已满再不大于maxPoolSize的情况下直接创建新的线程执行任务。
package threadpool;
import java.util.Calendar;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MyThreadPool {
public static void main(String[] args) {
BlockingQueue<Runnable> queue =
new ArrayBlockingQueue<Runnable>(3);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
1, // corePoolSize
2, // maxPoolSize
60, TimeUnit.SECONDS, queue);
Task t1 = new Task(1);
Task t2 = new Task(2);
Task t3 = new Task(3);
Task t4 = new Task(4);
Task t5 = new Task(5);
Task t6 = new Task(6);
executor.execute(t1);
executor.execute(t2);
executor.execute(t3);
executor.execute(t4);
//executor.execute(t5);
System.out.println("队列大小:"+queue.size());
executor.shutdown();
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Calendar.getInstance().get(Calendar.SECOND));
}
}
}
休眠2秒模拟任务执行耗时
package threadpool;
public class Task implements Runnable {
private Integer id;
public Task(Integer id) {
this.id = id;
}
@Override
public String toString() {
return "Task [id=" + id + "]";
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public void run() {
try {
Thread.sleep(2* 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("run taskId " + id);
}
}
先创建一个线程执行任务1,任务234加入等待队列,等待线程空闲后执行。
接下来将注释的去掉
executor.execute(t1);
executor.execute(t2);
executor.execute(t3);
executor.execute(t4);
executor.execute(t5);
在等待队列已满的情,并且任务数量没有大于maxPoolSize的情况下,直接创建两个线程。
当大于maxPoolSzie的时候会执行默认的拒绝策略。
可以看出使用有界队列的时候线程池的瓶颈是maxPoolSzie.
- 使用无界队列(LinkedBlockingQueue)自定义线程池,当任务数量小于corePoolSize的时候会直接创建线程执行任务,当任务数量大于corePoolSize又没有空闲的线程的时候会将任务无限制的加入到等待队列,如果任务创建的速度远大于任务执行的速度无界队列会保持快速增长,直到cpu资源耗尽。此时maxPoolSize没有任何作用。
自定义线程创建
package threadpool;
import java.util.concurrent.ThreadFactory;
public class MyThread implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
//设置为守护线程
t.setDaemon(true);
System.out.println("create "+t.getName());
return t;
}
}
ThreadFactory 是一个接口只有newThread(Runnable r),用来创建新的线程
自定义拒绝策略
简单的模拟一下
package threadpool;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
public class MyRejected implements RejectedExecutionHandler{
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
//应该记录在日志中,做一个任务调度
System.out.println(r.toString()+"is discard");
}
}
扩展线程池
针对以上的代码,我们很希望知道每个任务执行的状态,对线程池的运行状态进行跟踪,输出一些有助于调试的信息,例如任务的耗时。上述代码做了一个不是合适的记录,其实jdk已经为我们提供了这样的实现。
package threadpool;
import java.util.Calendar;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MyThreadPool {
public static void main(String[] args) {
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(3);
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, // corePoolSize
2, // maxPoolSize
60, TimeUnit.SECONDS,
queue,
Executors.defaultThreadFactory(),
new MyRejected()) {
long start;
@Override
protected void beforeExecute(Thread t, Runnable r) {
start = System.currentTimeMillis();
System.out.println("准备执行:" + ((Task) r).getId());
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
long end = System.currentTimeMillis() - start;
System.out.println("执行完毕:" + ((Task) r).getId() + "耗时:" + end + "毫秒");
}
@Override
protected void terminated() {
System.out.println("线程池退出");
}
};
for (int i = 1; i < 7; i++) {
Task t = new Task(i);
executor.execute(t);
}
System.out.println("队列大小:" + queue.size());
executor.shutdown();
/*
* while (true) { try { Thread.sleep(1000); } catch
* (InterruptedException e) { e.printStackTrace(); }
* System.out.println(Calendar.getInstance().get(Calendar.SECOND));
*
* }
*/
}
}
优化线程池的数量
Runtime.getRuntime().availableProcessors();
在线程池中寻找堆栈
package threadpool;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TraceTheadPoolExecutor extends ThreadPoolExecutor {
public TraceTheadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
private Runnable wrap(final Runnable task, final Exception clientTask, String threadName) {
return new Runnable() {
@Override
public void run() {
try {
task.run();
} catch (Exception e) {
clientTask.printStackTrace();
throw e;
}
}
};
}
private Exception clientTask() {
return new Exception("Client stack trace");
}
// 跟踪在哪里提交的任务
@Override
public void execute(Runnable command) {
super.execute(wrap(command, clientTask(), Thread.currentThread().getName()));
}
@Override
public Future<?> submit(Runnable task) {
return super.submit(wrap(task, clientTask(), Thread.currentThread().getName()));
}
}
自定义ThreadPoolExecutor使我们可以看见在哪里提交的任务
package threadpool;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TranceThreadPool {
public static void main(String[] args) {
ThreadPoolExecutor executor = new TraceTheadPoolExecutor(
0,
5,
0L,
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
for(int i=0;i<5;i++){
MyTask t = new MyTask(100,i);
executor.execute(t);
}
}
}
以上均为阅读源码和《java高并发城西设计》所做记录