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 。
线程池原理图:
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 ) )
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");
}
}