创建线程的方式以及Executors的四种线程池
Posted 陳英傑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建线程的方式以及Executors的四种线程池相关的知识,希望对你有一定的参考价值。
创建线程有几种方式?
面试常问的问题,一般回答3种方式,及格;如果你能具体的说4种,那你就满分了,第四种是通过Executors创建线程池。
先来说说创建线程的3种方式:
一、继承Thread类
public class ExtendsThread extends Thread
@Override
public void run()
super.run();
Log.e("ExtendsThread >>> ", "thread running");
public class MainActivity
public static void main(String[] args)
ExtendsThread thread = new ExtendsThread();
thread.start();
输出结果:
E/ExtendsThread >>>: thread running
二、实现Runnable接口
public class RunnableImp implements Runnable
@Override
public void run()
Log.e("RunnableImp >>> ", "runnable running");
public class MainActivity
public static void main(String[] args)
RunnableImp runnableImp = new RunnableImp();
new Thread(runnableImp).start();
输出结果:
E/RunnableImp >>>: runnable running
三、实现Callable接口
public class CallableImp implements Callable<String>
@Override
public String call() throws Exception
Thread.sleep(3000);
Log.e("CallableImp >>> ", "Callable running");
return "I`m CallableImp";
public class MainActivity
public static void main(String[] args)
// 3、实现Callable接口
try
CallableImp callableImp = new CallableImp();
FutureTask<String> futureTask = new FutureTask<>(callableImp);
new Thread(futureTask).start();
// 如果CallableImp中任务未执行完,get()方法会阻塞
Log.e("CallableImp 返回结果 >>> ", futureTask.get());
catch (Exception e)
e.printStackTrace();
输出结果:
E/CallableImp >>>: Callable running
E/CallableImp 返回结果 >>>: I`m CallableImp
Runnable和Callable区别:
Runnable:
1、run方法没有返回值;
2、可以作为Thread的目标对象;
3、run方法不能抛出异常;
Callable:
1、call方法有返回值,通过FutureTask.get()方法获取,如果调用get方法时call方法没有执行完,get方法会阻塞;
2、不能作为Thread的目标对象,RunnableFuture才可以,因为RunnableFuture是一个继承了Runnable和Future的接口,FutureTask是RunnableFuture的一个实现类,一般用FutureTask结合Callable使用;
3、call方法可以抛出异常;
四、Executors创建线程池
1、CachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
private void cachedThreadPool()
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++)
final int index = i;
cachedThreadPool.execute(new Runnable()
@Override
public void run()
System.out.println("CachedThreadPool >> running " + index + ", Thread = " + Thread.currentThread().toString());
try
Thread.sleep(1000);
catch (Exception e)
e.printStackTrace();
);
打印结果:
CachedThreadPool >> running 0, Thread = Thread[pool-1-thread-1,5,main]
CachedThreadPool >> running 1, Thread = Thread[pool-1-thread-2,5,main]
CachedThreadPool >> running 2, Thread = Thread[pool-1-thread-3,5,main]
CachedThreadPool >> running 3, Thread = Thread[pool-1-thread-4,5,main]
CachedThreadPool >> running 4, Thread = Thread[pool-1-thread-5,5,main]
CachedThreadPool >> running 5, Thread = Thread[pool-1-thread-6,5,main]
CachedThreadPool >> running 6, Thread = Thread[pool-1-thread-7,5,main]
CachedThreadPool >> running 7, Thread = Thread[pool-1-thread-8,5,main]
CachedThreadPool >> running 8, Thread = Thread[pool-1-thread-9,5,main]
CachedThreadPool >> running 9, Thread = Thread[pool-1-thread-10,5,main]
每次执行的Thread信息都不一样,说明每执行一次都创建了一个新的线程。
2、FixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
定长线程池的大小最好根据系统资源进行设置。
private void fixedThreadPool()
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++)
final int index = i;
fixedThreadPool.execute(new Runnable()
@Override
public void run()
System.out.println("FixedThreadPool >> running " + index + ", Thread = " + Thread.currentThread().toString());
try
Thread.sleep(1000);
catch (Exception e)
e.printStackTrace();
);
打印结果:
FixedThreadPool >> running 0, Thread = Thread[pool-1-thread-1,5,main]
FixedThreadPool >> running 1, Thread = Thread[pool-1-thread-2,5,main]
FixedThreadPool >> running 2, Thread = Thread[pool-1-thread-3,5,main]
FixedThreadPool >> running 3, Thread = Thread[pool-1-thread-4,5,main]
FixedThreadPool >> running 4, Thread = Thread[pool-1-thread-5,5,main]
FixedThreadPool >> running 5, Thread = Thread[pool-1-thread-4,5,main]
FixedThreadPool >> running 6, Thread = Thread[pool-1-thread-3,5,main]
FixedThreadPool >> running 9, Thread = Thread[pool-1-thread-2,5,main]
FixedThreadPool >> running 8, Thread = Thread[pool-1-thread-1,5,main]
FixedThreadPool >> running 7, Thread = Thread[pool-1-thread-5,5,main]
从执行的Thread的信息发现不规律,但是根据线程ID发现只有5个线程,也就是说哪个线程空闲哪个线程去执行任务。
3、SingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
private void singleThread()
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 20; i++)
final int index = i;
singleThreadExecutor.execute(new Runnable()
@Override
public void run()
System.out.println("SingleThreadExecutor >> running " + index + ", Thread = " + Thread.currentThread().toString());
try
Thread.sleep(1000);
catch (Exception e)
e.printStackTrace();
);
打印结果:
SingleThreadExecutor >> running 0, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 1, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 2, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 3, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 4, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 5, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 6, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 7, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 8, Thread = Thread[pool-1-thread-1,5,main]
SingleThreadExecutor >> running 9, Thread = Thread[pool-1-thread-1,5,main]
从执行的Thread信息发现ID都是同一个,此线程池中只有一个线程,任务是按顺序执行的。
4、ScheduleThreadPool
创建一个定长线程池,支持定时及周期性任务执行。
它有4个可调用方法:
// 1、延迟执行一个Runnable接口的实现
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);
// 2、延迟执行一个Callable接口的实现
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);
// 3、延迟之后以固定频率执行一个Runnable接口的实现
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
// 4、延迟之后开始执行一个Runnable接口的实现,之后的每次任务都是在前一个任务结束后延迟delay再执行
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);
/*
3和4的区别:
3是不考虑每个任务的耗时,4要考虑每个任务的耗时,画一个时间轴来理解:
比如 scheduleAtFixedRate(runnable, 1000, 1000, TimeUnit.MILLISECONDS)
和 scheduleWithFixedDelay(runnable, 1000, 1000, scheduleWithFixedDelay)
假如每个任务耗时1秒,两者执行的时间轴(每个_代表1秒,|表示执行任务):
3: _|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|...
4: _|_ _|_ _|_ _|_ _|_ _|_ _|_ _|_ _|...
/
例子:
private void scheduledThreadPool()
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
// scheduledThreadPool.scheduleWithFixedDelay(new Runnable()
scheduledThreadPool.scheduleAtFixedRate(new Runnable()
@Override
public void run()
System.out.println(new Date().toString() + "<< ScheduledThreadPool >> running " + index + ", Thread = " + Thread.currentThread().toString());
index++;
try
Thread.sleep(1000);
catch (Exception e)
e.printStackTrace();
, 1000, 1000, TimeUnit.MILLISECONDS);
方法3打印结果:
Thu Nov 05 15:59:17 CST 2020<< ScheduledThreadPool >> start
Thu Nov 05 15:59:18 CST 2020<< ScheduledThreadPool >> running 0, Thread = Thread[pool-1-thread-1,5,main]
Thu Nov 05 15:59:19 CST 2020<< ScheduledThreadPool >> running 1, Thread = Thread[pool-1-thread-1,5,main]
Thu Nov 05 15:59:20 CST 2020<< ScheduledThreadPool >> running 2, Thread = Thread[pool-1-thread-2,5,main]
Thu Nov 05 15:59:21 CST 2020<< ScheduledThreadPool >> running 3, Thread = Thread[pool-1-thread-1,5,main]
Thu Nov 05 15:59:22 CST 2020<< ScheduledThreadPool >> running 4, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 15:59:23 CST 2020<< ScheduledThreadPool >> running 5, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 15:59:24 CST 2020<< ScheduledThreadPool >> running 6, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 15:59:25 CST 2020<< ScheduledThreadPool >> running 7, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 15:59:26 CST 2020<< ScheduledThreadPool >> running 8, Thread = Thread[pool-1-thread-3,5,main]
Thu Nov 05 15:59:27 CST 2020<< ScheduledThreadPool >> running 9, Thread = Thread[pool-1-thread-3,5,main]
从开始到之后的每次延迟任务间隔都是1秒;
方法4打印结果:
Thu Nov 05 16:00:55 CST 2020<< ScheduledThreadPool >> start
Thu Nov 05 16:00:56 CST 2020<< ScheduledThreadPool >> running 0, Thread = Thread[pool-1-thread-1,5,main]
Thu Nov 05 16:00:58 CST 2020<< ScheduledThreadPool >> running 1, Thread = Thread[pool-1-thread-1,5,main]
Thu Nov 05 16:01:00 CST 2020<< ScheduledThreadPool >> running 2, Thread = Thread[pool-1-thread-2,5,main]
Thu Nov 05 16:01:02 CST 2020<< ScheduledThreadPool >> running 3, Thread = Thread[pool-1-thread-1,5,main]
Thu Nov 05 16:01:通过Executors创建线程池的四种方式和注意小点