纵览三种实现方式:
- 实现Runnable接口
- 继承Thread类
- 实现Callable<V>接口,结合FutureTask<V>
文末附加线程池操作。
一、实现Runnable接口
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getId() + " Hello Runnable!");
}
public static void main(String[] args) throws Exception {
// 一个线程哪够,来仨(sa)...
new Thread(new MyRunnable()).start();
new Thread(new MyRunnable()).start();
new Thread(new MyRunnable()).start();
}
}
如上类图,MyRunnable实现了Runnable接口。其中Runnable由@FunctionalInterface注解标注,也就是可以用函数式编程的方式简写,简写后如下:
new Thread(() -> System.out.println(Thread.currentThread().getId() + " Hello Runnable!")).start();
二、继承Thread类
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getId() + " Hello Thread!");
}
public static void main(String[] args) {
new MyThread().start();
new MyThread().start();
new MyThread().start();
}
}
这个很简单,Thread实现了Runnable接口,以继承的方式实现,在java里边不像接口那么好用,毕竟类是单继承的。
三、实现Callable<V>接口,结合FutureTask<V>
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return Thread.currentThread().getId() + " Hello Callable!";
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 3; i++) {
Callable<String> callable = new MyCallable();
FutureTask<String> task = new FutureTask<>(callable);
new Thread(task).start();
// 获取异步线程返回的数据
System.out.println(task.get());
}
}
}
结合如上类图,以及Callable源码,它的源码很简单,只定义了一个带返回值的call方法,和Runnable完全没关系,所以说直接用Callable不能实现多线程的。
此时引入了另一个类FutureTask,它的构造方法中可以接收Callable,再看它的类图,间接实现了Runnable接口,这下豁然开朗。
Callable也由@FunctionalInterface注解标注,所以也能简写,如下:
Callable<String> callable = () -> Thread.currentThread().getId() + " Hello Callable!";
// 下边的和之前一样
FutureTask<String> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
System.out.println(futureTask.get());
四、附加线程池操作
IDEA安装了阿里编码规范插件,new Thread(...) ,总会警告,索性用线程池好了。
// 创建线程工厂,并设置线程名字格式
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("thread-pool-%d").build();
ExecutorService singleThreadPool = new ThreadPoolExecutor(12, 24,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(1024), threadFactory, new ThreadPoolExecutor.AbortPolicy());
for (int i = 0; i < 12; i++) {
singleThreadPool.execute(() -> System.out.println(Thread.currentThread().getName()));
}
singleThreadPool.shutdown();
- 其中ThreadFactoryBulider用的是Google的一个java开源库
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>23.6-jre</version> </dependency>
- ThreadPoolExecutor构造参数
- ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) - corePoolSize:核心线程数;
- maximumPoolSize:线程池所能容纳的最大线程数;
- keepAliveTime:非核心线程的闲置超时时间,超过这个时间就会被回收;
- unit:指定keepAliveTime的单位,如 TimeUnit.SECONDS;
- workQueue:线程池中的任务队列;通俗说就是线程超出核心线程数量后,线程怎么继续执行的策略;
- threadFactory:线程工厂,提供创建新线程的功能;
- handler:线程池对拒绝任务的策略;ThreadPoolExecutor里面定义了 4 种 handler 策略:
- CallerRunsPolicy :这个策略重试添加当前的任务,他会自动重复调用 execute() 方法,直到成功。
- AbortPolicy :对拒绝任务抛弃处理,并且抛出异常。
- DiscardPolicy :对拒绝任务直接无声抛弃,没有异常信息。
- DiscardOldestPolicy :对拒绝任务不抛弃,而是抛弃队列里面等待最久的一个线程,然后把拒绝任务加到队列。
- ThreadPoolExecutor(int corePoolSize,
- ExecutorService 的 execute方法接受参数为Runnable,所以上边用到的Thread、FutureTask等均可。
完。。。
来源:oschina
链接:https://my.oschina.net/u/2811278/blog/1924376