Thread 类和 Runnable 接口; callable接口与Future、线程池结合使用
Thread 类和 Runnable 接口
如果一个类继承 Thread类,则不适合于多个线程共享资源,而实现了 Runnable 接口,就可以方便的实现资源的共享。
至于为什么实现Runnable可以共享资源,是因为线程调用的是同一个对象。
Runnable runable = new Runnable(){
@Override
public void run() { }
};
Thread th1 = new Thread(runable);
Thread th2 = new Thread(runable);
Thread th3 = new Thread(runable);
而继承Tread的类只能通过对象的start方法,也就是一个对象启动一次。
Thread join
方法
join():指等待调用的线程终止。
join()
在启动线程后调用,join()
的作用是:“等待该线程终止”,即主线程等待子线程的终止。只有等到子线程结束了,join()方法后面的代码才能执行。
callable接口与Future、线程池结合使用
ExecutorService Future Callable
ExecutorService
继承了Excutor接口,Excutor接口只有一个excute(Runnable)方法。
![](http://www.yiyehu.tech/wp-content/uploads/2020/07/image-49.png)
submit方法提交Callable返回Future。
Future可以通过get方法来获取callable返回的结果(如果未执行完成,调用get方法时阻塞获取结果)。Future唯一实现类是FutureTask。
![](http://www.yiyehu.tech/wp-content/uploads/2020/07/image-50.png)
Executors
关于创建线程池,Java提供了ThreadPoolExecutor这个类,也提供了使用Executors创建几个固定场景下的线程池方法。
方法 | 参数 | 场景 | workQueue |
newFixedThreadPool | nThreads:corePoolSize和maxPoolSize; threadFactory:线程工厂类 |
创建一个线程池,在需要时使用提供的ThreadFactory创建新线程, 该线程池重用固定数量的线程操作共享的无边界队列。 如果在所有线程都处于活动状态时提交了其他任务,则它们将在队列中等待,直到有一个线程可用为止。 如果任何线程在关闭前的执行过程中由于失败而终止,那么在需要执行后续任务时,将有一个新的线程替代它。 池中的线程将一直存在,直到显式地ExecutorService#shutdown |
LinkedBlockingQueue |
newSingleThreadExecutor | threadFactory | 创建一个执行器,该执行器使用单个工作线程操作一个未绑定队列。 (但是请注意,如果这个线程在关闭之前由于执行失败而终止,那么在需要执行后续任务时,一个新的线程将取代它。) 任务保证按顺序执行,并且在任何给定时间内活动的任务不超过一个。 与等效的{@code newFixedThreadPool(1)}不同,返回的执行器保证不会被重新配置以使用额外的线程。 |
LinkedBlockingQueue |
newCachedThreadPool | 0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory |
创建一个线程池,该线程池根据需要创建新线程,但在可用时将重用之前构建的线程,并在需要时使用提供的ThreadFactory创建新线程。 | SynchronousQueue |
newScheduledThreadPool | corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue(), threadFactory |
创建一个线程池,该线程池可以安排命令在给定的延迟后运行或定期执行 | DelayedWorkQueue |
newWorkStealingPool | new ForkJoinPool (parallelism, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); |
创建一个线程池,该线程池维护足够的线程来支持给定的并行级别,并可以使用多个队列来减少争用。 并行性级别对应于活动参与或可用参与任务处理的最大线程数。线程的实际数量可以动态地增加或减少。工作窃取池不能保证提交任务的执行顺序。 |
建议使用ThreadPoolExecutor来创建线程池,因为上面提到的方法都是使用无界队列来实现的workQueue,所以有大概率可能会导致OOM。
ThreadPoolExecutor
public class ThreadPoolExecutor extends AbstractExecutorService
创建线程池有两种方法:Excutors 和 ThreadPoolExecutor,阿里开发手册上建议使用ThreadPoolExecutor而不是Excutors。因为Excutors容易考虑不到资源消耗,容易OOM。Excutors中还是依靠ThreadPoolExecutor创建的线程池,只不