Java 中如何创建线程

Java 创建线程有四种方式:继承 Thread,实现 Runnable 接口,线程池,实现 Callable 接口

Thread 和 Runnable,首先 Runnable 是接口,实现了该接口的类还可以继承其他类,更灵活;其次,Runnable 任务可以在 Executors 中或 ExecutorService 提交运行

Callable 和 Runnable 区别

  • Callable 定义的方法是 call,而 Runnable 定义的方法是 run

  • Callable 的 call 方法可以有返回值,Runnable 的 run 方法没有返回值

  • Callable 的 call 方法可以抛出异常,Runnable 的 run 方法不能抛出异常

线程池的用法

当线程使用的时间远远大于线程创建和销毁的时间时就应当使用线程池

Java 里面线程池的顶级接口是 Executor,但是严格意义上讲 Executor 并不是一个线程池,而是一个执行线程的工具,真正的线程池接口是 ExecutorService

Executor 是一个顶级接口,在它里面只声明了一个方法 execute(Runnable),返回值为 void,参数为 Runnable 类型,从字面意思可以理解,就是用来执行传递进去的任务的

ExecutorService 接口继承了 Executor 接口,并声明了一些方法:submit、invokeAll、invokeAny 以及 shutDown 等

抽象类 AbstractExecutorService 实现了 ExecutorService 接口,基本实现了 ExecutorService 中声明的所有方法

要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池的不是最优的。因此在 Executor 类里面提供了一些静态工厂,生成一些常用的线程池。

newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务

  • 如果这个唯一的线程因为异常结束,那么会有一个新的线程来接替它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行

newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小

  • 线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程

newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程数,那么会回收部分空闲(60 秒不执行)的线程

  • 当任务数增加时,此线程又可以智能的添加新线程来处理任务。

  • 此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程数

newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求

这些方法的返回值是 ExecutorService 对象,该对象表示一个线程池,可以执行 Runnable 对象或 Callable 对象代表的线程

创建了线程池后下一步就是提交任务了,线程池提交任务有两种方法,一个是execute,另一个是 submit。二者的区别在于;

  • executor 没有返回值,出现异常直接抛出

  • submit 会返回 Future 对象,异常信息会被捕获存储,需要使用 get 方法查看

Furture 对象:接收异步线程返回的结果,可以使用 furture.get() 获取返回值

  • 不带参数的 get 方法是阻塞方法,只要线程未返回结果就会一直阻塞

可以使用 isDone() 方法判断线程是否结束

-----------本文结束感谢您的阅读-----------
0%