Java线程池相关类
Executor
定义了最常见的线程池接口,execute(Runnable command)
。
public interface Executor {
void execute(Runnable command);
}
ExecutorService
线程池接口类。
ThreadPoolEexcutor
最为常用的线程池。
/**
* corePoolSize : 活跃线程数
* maximumPoolSize : 线程总数
* keepAliveTime,unit : 非活跃线程在keepAliveTime个unit之后会被回收
* workQueue : 工作队列
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {}
Executors
工厂类,利用工厂方法可以生产成各种各样的线程池,生产出各种参数的ThreadPoolExecutor,比如newFixedThreadPool(int nThreads)
:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
ThreadPoolExecutor
- 当线程池执行一个runnable时,它会先去检查线程池里的线程数是否小于corePool的定义的线程数,如果小于它,不管这些线程是否空闲,都会不断创建新线程,直到线程池里的线程数等于corePool。
- 当线程池的线程数已经等于corePool,如果还有新任务,但是线程池里面有空闲线程,那么会用这些空闲线程执行这些任务。
- 如果线程池里面已经没有空闲线程了,会把任务放到工作队列里面;当有线程闲下来的时候,会从工作队列里面取任务下来执行。
- 当没有空闲线程,并且工作队列也已经满了。这时会从创建新线程来执行这些任务,直到线程池的线程数等于maximumPool
- 如果工作的线程数已经达到maximumPoolSize,并且工作队列也已经被塞满了,这时如果还来新任务的话就会报异常。
- 当线程不再执行任务的时候,过了keepAliveTime,如果线程池总数大于corePoolSize,就会被回收,直到线程池的总数等于corePoolSize。
假设corePool = 3, maximumPool = 6, 工作队列大小为10个,假设这些线程都需要足够的时间才能执行完毕,当加入20个任务的时候,线程执行顺序应该是这样子的:先执行1-3,然后把4-13放到工作队列里面,然后再执行14-16,任务17-20会抛出异常。
Callable和Future
Callable 和 Runnable都可以作为线程的执行任务,只是Callable有返回值,而Runnable没有返回值;Callable的返回值可以用Future来接收,然后用get()来使用。比如:
ExecutorService pool = Executors.newFixedThreadPool(10);
Future<String> future = pool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return Thread.currentThread().getName();
}
});
System.out.println(future.get());
future.get()
会使线程阻塞,一直到call执行完。
FutureTask
ExecutorService pool = Executors.newFixedThreadPool(10);
FutureTask futureTask = new FutureTask(new Callable<String>() {
@Override
public String call() throws Exception {
return Thread.currentThread().getName();
}
});
pool.submit(futureTask);
//用普通线程的方式
new Thread(futureTask).start();
if(futureTask.isDone()){
System.out.println(futureTask.get());
}