1.示例代码: Runnable + ThreadPoolExecutor
首先创建一个
Runnable
接口的实现类(当然也可以是
Callable
接口,我们上面也说了两者的区
别。)
MyRunnable.java
import java.util.Date;
public class MyRunnable implements Runnable {
private String command;
public MyRunnable (String s){
this.command = s;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Start. Time = " + new Date());
processCommand();
System.out.println(Thread.currentThread().getName() + " End. Time = " + new Date());
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return this.command;
}
}
编写测试程序,我们这里以阿里巴巴推荐的使用
ThreadPoolExecutor
构造函数自定义参数的方式来
创建线程池。
ThreadPoolExecutorDemo.java
public class CallableDemo {
private static final int CORE_POOL_SIZE = 5;
private static final int MAX_POOL_SIZE = 10;
private static final int QUEUE_CAPACITY = 100;
private static final Long KEEP_ALIVE_TIME = 1L;
public static void main(String[] args) {
//使用阿里巴巴推荐的创建线程池的方式
// 通过ThreadPoolExecutor构造函数自定义参数创建
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(QUEUE_CAPACITY),
new ThreadPoolExecutor.CallerRunsPolicy());
for (int i = 0; i < 10; i++) {
//创建WorkerThread对象(WorkerThread类实现了Runnable 接口)
Runnable worker = new MyRunnable("" + i);
//执行Runnable
executor.execute(worker);
}
//终止线程池
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("Finished all threads");
}
}
可以看到我们上面的代码指定了:
1.
corePoolSize
:
核心线程数为
5
。
2.
maximumPoolSize
:最大线程数
10
3.
keepAliveTime
:
等待时间为
1L
。
4.
unit
:
等待时间的单位为
TimeUnit.SECONDS
。
5.
workQueue
:任务队列为
ArrayBlockingQueue
,并且容量为
100;
6.
handler
:
饱和策略为
CallerRunsPolicy
。
线程池原理图:
![](https://img-blog.csdnimg.cn/2251ba8bbaff48f38a90dc599be720eb.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAT2RhZGFQbHVz,size_20,color_FFFFFF,t_70,g_se,x_16)
2.Runnable vs Callable
Runnable
自
Java 1.0
以来一直存在,但
Callable
仅在
Java 1.5
中引入
,
目的就是为了来处理
Runnable
不支持的用例。
Runnable
接口
不会返回结果或抛出检查异常,但是
Callable
接口
可以。
所以,如果任务不需要返回结果或抛出异常推荐使用
Runnable
接口
,这样代码看起来会更加简洁。
工具类
Executors
可以实现
Runnable
对象和
Callable
对象之间的相互转换。
(
Executors.callable
(
Runnable task
)或
Executors.callable
(
Runnable task
,
Object
resule
)
)
3.
execute()
vs
submit()
execute()
方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;
submit()
方法用于提交需要返回值的任务。线程池会返回一个
Future
类型的对象,通过这个
Future
对象可以判断任务是否执行成功
,并且可以通过
Future
的
get()
方法来获取返回值,
get()
方法会阻塞当前线程直到任务完成,而使用
get
(
long timeout
,
TimeUnit unit
)
方法
则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。
shutdown()
VS
shutdownNow()
shutdown()
:
关闭线程池,线程池的状态变为
SHUTDOWN
。线程池不再接受新任务了,但是队
列里的任务得执行完毕。
shutdownNow()
:
关闭线程池,线程的状态变为
STOP
。线程池会终止当前正在运行的任务,并
停止处理排队的任务并返回正在等待执行的
List
。
i
sTerminated()
VS
isShutdown()
isShutDown
当调用
shutdown()
方法后返回为
true
。
isTerminated
当调用
shutdown()
方法后,并且所有提交的任务完成后返回为
true
4.Callable + ThreadPoolExecutor 示例代码
import java.util.concurrent.Callable;
public class MyCallable implements Callable {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return Thread.currentThread().getName();
}
}
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorDemo {
private static final int CORE_POOL_SIZE = 5;
private static final int MAX_POOL_SIZE = 8;
private static final int QUEUE_CAPACITY = 10;
private static final Long KEEP_ALIVE_TIME = 1L;
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(QUEUE_CAPACITY),
new ThreadPoolExecutor.CallerRunsPolicy());
for (int i = 0; i < 40; i++) {
Runnable worker = new MyRunnable(">>" + i);
threadPoolExecutor.execute(worker);
System.out.println("worker>>" + i);
}
//终止线程
threadPoolExecutor.shutdown();
while (!threadPoolExecutor.isTerminated()){
}
System.out.println("Finished All Threads");
}
}