实现多线程的三种方式:
第一种方式:继承Thread类型
- 创建一个继承Thread类的子类;
- 重写Thread类中的run(),将此线程要执行的操作声明在run();
- 创建Thread的子类的对象;
- 调用此对象的start():①启动线程,②调用当前线程的run()方法。
第二种方式:实现Runnable接口
- 创建一个实现Runnable接口的类
- 实现Runnable接口中的抽象方法:run():将创建的线程要执行的操作声明在此方法中
- 创建Runnable接口实现类的对象
- 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
- 调用Thread类中的start():① 启动线程 ② 调用线程的run() —>调用Runnable接口实现类的run()
第三种方式:实现Callable接口
应用场景:当父线程想要获取子线程的运行结果时;
call()方法抛出Exception异常,且返回一个指定的泛型类对象。
- 创建Callable子类的实例化对象;
- 创建FutureTask对象,并将Callable对象传入FutureTask的构造方法中;
- 实例化Thread对象,并在构造方法中传入FutureTask对象;
- 启动线程;
第四种方式:线程池创建
许多请求到达服务器,导致频繁创建新线程,销毁新线程,浪费了服务器的开销;ExecutorService是一个线程池,多个任务复用线程,避免了线程的重复创建和销毁,并且可以规定线程数目,请求数目超过阈值时强制等待直到有空闲线程。
当我们有任务需要多线程来完成时,将任务(实现Runnable、callable接口、继承Thread类的对象)提交给ExecutorService。
- corePoolSize:核心线程数,一旦创建将不会释放。
- maximumPoolSize:最大线程数,允许创建的最大线程数量。
- keepAliveTime:当线程空闲时,所允许保存的最大时间。只针对于非核心线程。
- unit : 时间单位,TimeUnit.SECONDS等。
- workQueue: 任务队列,用于保存等待执行的任务的阻塞队列。可以选择一下几个阻塞队列。
-
- 1、ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,必须设置容量。此队列按FIFO(先进先出)原则对元素进行排序。
-
- 2、LinkedBlockingQueue: 一个基于链表结构的阻塞队列,可以设置容量,此队列按FIFO排序元素,吞吐量通常要高于ArrayBlockingQueue。
-
- 3、SynchronousQueue:一个不存储元素的阻塞队列。每个插入offer操作必须等到另一个线程调用移除poll操作,否则插入操作一直处于阻塞状态,吞吐量高于链表结构的队列。
-
- 4、PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
- threadFactory:线程工厂,用于创建线程。
- handler:当线程边界和队列容量已经达到最大时,用于处理阻塞时的程序。