1.线程的生命周期
新建-------->就绪---(阻塞)----->运行------>死亡
在运行后有一个阻塞状态,主要是因为调用sleep和wait方法产生的,在阻塞线程抢到cpu的后会回到就绪状态。
2.线程创建的三种方法
- 创建类继承Thread,重新run方法,调用start方法开启线程。
- 创建类实现Runnable接口,重写run方法,创建Thread传入自己定义的runnable类,调用start方法
- 创建类实现Callable接口,重写call方法,创建线程池调用submit()方法,传入参数为自定义的Callable,获得返回值Future对象,调用Future对象的get()方法获取call()方法执行完后的值。
三种创建方法的区别
因为在java是单继承,多实现。实现 Runnable 接口还可以继承其他类,而使用继承 Thread 就不能继承其他类了。所以当你想创建一个线程又希望继承其他类的时候就该选择实现 Runnable 接口的方式。
Callable 执行的方法是 call() ,而 Runnable 执行的方法是 run()。
call() 方法有返回值还能抛出异常, run() 方法则没有没有返回值,也不能抛出异常。
3.解决多线程安全问题
使用同步代码块
4.线程池的创建
一般是创建 ThreadPoolExecutor(参数);
其中参数为:
- int CorePoolSize:核心线程数量。这几个核心线程,只是在没有用的时候,也不会被回收。
- int maxiumPoolSize:线程池中可以容纳的最大线程的数量。
- long keepAliveTime:线程池中非核心线程存活的时间。
- TimeUnit unit : 计算线程保存时间的类。
- BlockingQueue<Runnable> workQueue:等待队列,任务可以储存在任务队列中等待被执行,执行的是FIFIO原则(先进先出)。
- ThreadFactory threadFactory :创建线程的线程工厂。
- RejectedExecutionHandler handler :拒绝策略,当任务满了的时候会选择拒绝执行。
5.常见线程池
CachedThreadPool:可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于耗时少,任务量大的情况。
SecudleThreadPool:周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。
SingleThreadPool:只有一条线程来执行任务,适用于有顺序的任务的应用场景。
FixedThreadPool:定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程。
6.如何让线程按顺序执行
- 使用线程的join方法。
- 使用线程池 SingleThreadPool。