因为在答题系统中写到了匹配功能,之前是单纯的使用集合完成的.初期可能没问题,但如果后期用户量增加后可能会出现线程安全问题.因此想改为通过多线程实现,在此记录一下.
从网上搜了很多,大部分都是讲概念性的东西,对于实际开发应用感觉还是不知道如何入手,于是从github上下了一个关于创建线程池的demo,以此入手来学习多线程.
首先线程池最上方的接口是Executor,这个接口定义了一个核心方法execute(Runnabel command),这个方法最后被ThreadPoolExecutor类实现,这个方法是用来传入任务的。而且ThreadPoolExecutor是线程池的核心类,此类的构造方法如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
这几个参数分别代表:
corePoolSize:核心线程池的大小,如果核心线程池有空闲位置,这是新的任务就会被核心线程池新建一个线程执行,执行完毕后不会销毁线程,线程会进入缓存队列等待再次被运行。
maximunPoolSize:线程池能创建最大的线程数量。如果核心线程池和缓存队列都已经满了,新的任务进来就会创建新的线程来执行。但是数量不能超过maximunPoolSize,否侧会采取拒绝接受任务策略,我们下面会具体分析。
keepAliveTime:非核心线程能够空闲的最长时间,超过时间,线程终止。这个参数默认只有在线程数量超过核心线程池大小时才会起作用。只要线程数量不超过核心线程大小,就不会起作用。
unit:时间单位,和keepAliveTime配合使用。
workQueue:缓存队列,用来存放等待被执行的任务。
threadFactory:线程工厂,用来创建线程,一般有三种选择策略。
ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;
handler:拒绝处理策略,线程数量大于最大线程数就会采用拒绝处理策略,四种策略为
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
关于线程池的关闭:
executor.shutdown(); 会进入shutDown状态,不会接受新的任务,会等到缓存队列中的任务执行完毕.
executor.shutdownNow(),不会接受新的任务,并且尝试关闭正在执行的任务(强制关闭)
以上内容参考原文地址:线程池的使用(线程池重点解析)介绍的非常详细,想了解更多的可以去看看.
然后在demo中看到了Future和callable接口,
我们都知道,一般创建线程有两种方式:
1.继承threadl类.
2.实现Runnable接口.
但是这两种方式都存在一个问题,就是在线程任务执行结束后无法获取执行结果。我们一般只能采用共享变量或共享存储区以及线程通信的方式实现获得任务结果的目的。
而future和callable就是第三种创建线程的方式
我们看到callable是有泛型返回值V的
而future的作用可以理解为不需要等待返回结果再执行下一步,我只需要将任务交给future就可以去做别的事情了.
future接口的实现类有futureTask类,futureTask类结合callable接口使用,当我们把callable接口中的call方法交给线程执行时,我们可以继续做其他事情,futureTask类可以获取call方法返回值,它的作用就是控制Callable的call方法的执行过程。其核心思想:一个方法f,计算过程可能非常耗时,等待f返回,显然不明智。可以在调用f的时候,立马返回一个Future,可以通过Future这个数据结构去控制方法f的计算过程。
这个解释比较清晰一点,
出自https://blog.youkuaiyun.com/qq_40718168/article/details/84581137
代码:
mycallable代码: