笔者今天看到一个有趣的面试题,如何让多个线程按照既定的顺序依次执行?比如每个线程输出一个整数,
那么期望就是这样的:0,1,2,3,4,5,6,7,8,9.而不是0,2,4,1,3,5,8,7,9,6
乍一看,这不是反人性的考题吗?多线程本来就以乱序执行出名的。稍加思索,想到3种解决方案,分别用代码实现之。
方法1: 使用join方法
代码如下:
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1...");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2...");
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t3...");
}
});
try {
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
方法2:使用newSingleThreadExecutor
ExecutorService pool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 1000; ++i) {
final int number = i;
pool.execute(() -> {
System.out.println("I am " + number);
});
}
pool.shutdown();
方法3:使用ThreadPoolExecutor,设置它的核心线程数为1
ExecutorService pool = new ThreadPoolExecutor(1, 1000, 300, TimeUnit.SECONDS, new LinkedBlockingQueue(1000), Executors.defaultThreadFactory(), newThreadPoolExecutor.AbortPolicy());
for (int i = 0; i < 1000; ++i) {
final int number = i;
pool.execute(() -> {
System.out.println("I am " + number);
});
}
pool.shutdown();
public ThreadPoolExecutor
(int corePoolSize,//核心线程数:当一个任务提交到线程池中,如果当前运行的线程数量小于核心线程数,会新开一个线程来执行任务
int maximumPoolSize,//最大线程数:当大于核心线程数时,可以设置一个最大线程数
long keepAliveTime,//最大空闲时间(存活时间):当一个任务没有运行时候,task可以存活的时间
TimeUnit unit,//时间单位:枚举类型,可设置天、小时、时分秒等
BlockingQueue<Runnable> workQueue,//任务队列(临时缓冲区):当任务达到核心线程数量时,再有task提交到线程池需要在任务队列先排队,当任务队列满了之后会根据最大线程数创建新线程
ThreadFactory threadFactory,//线程工厂:创建线程的工厂
RejectedExecutionHandler handler) {//饱和处理机制:当核心线程数、最大线程数贺任务队列都满了需要处理的事情
各个参数含义如下:
假设某银行营业部有两名正式工,一名临时工,一个空闲等待座位,当有a、b、c、d客户依次来办理业务,a、b由两名正式工接待工作,c客户由临时工接待,d客户在座位等待,如果营业部是线程池,核心线程数(两名正式工)就是2,最大线程数(外加临时工)为3,任务队列(座位缓冲区)为1,当此时来了客户e办理业务,银行只能按照饱和处理机制拒绝接待客户e,当营业部临时工空闲时间超过1个小时后,经理就会让临时工(线程销毁)下班,有一个allowCoreThreadTimeOut变量控制是否允许销毁核心线程,默认为false,即时正式工闲着也不得提前下班