实现线程的方式有几种?
- 继承Thread类并重写run方法。
- 实现Runnable接口
- 实现Callable接口
- 线程池
Thread和runnable的区别?
- Thread只能单继承 Runnable可以多实现
- 线程池只能接受Runnable或者Callable接口的实现 不能接受Thread的方式
- 实现runnable的方式适合做资源共享 而Thread的方式不能资源共享
runnable和Callable的区别?
- Runnable:没有返回值,不能抛异常。
- Callable:有返回值, 可以抛出异常。
有几种线程池 特点是什么? 队列的特点
- FixedThreadPool(定长线程池):拥有固定数量线程的线程池,适用于需要限制当前线程数量的场景,保证资源的控制,使用的无界队列存储任务。
- SingleThreadExecutor(单例线程池):只有一个线程的线程池,保证所有任务按顺序执行,使用的无界队列存储任务。
- CachedThreadPool(缓存线程池):根据场景需要创建新线程的线程池,对于大量短生命周期的异步任务非常合适,使用的同步队列。
- ScheduledThreadPool(定时线程池):可以延迟执行或定期执行任务的线程池,使用的延迟队列。
队列特点:线程池通常使用阻塞队列作为任务的存放地,阻塞队列可以有效地控制任务的数量,并且提供了线程安全。
无界队列(LinkedBlockingQueue):理论上可以容纳任意数量的待执行任务。
有界队列(ArrayBlockingQueue):容量固定,提交新任务时如果队列已满,则线程池会创建新线程处理任务(直到达到最大线程数)。
同步队列(SynchronousQueue):没有容量,通常配合可缓存线程池使用,适用于传递性任务。
延迟队列(DelayedWorkQueue): 能够按照元素的优先级进行排序和出队。
线程池的工作原理?
当提交一个新任务到线程池时,具体的执行流程如下:
- 当我们提交任务,线程池会根据核心线程数大小创建核心线程执行任务
- 当任务的数量超过核心线程数数量,后续的任务将会进入阻塞队列
- 当阻塞队列也满了之后,那么将会继续创建非核心线程来执行任务,如果任务处理完成,空闲的非核心线程会在存活的指定时间之后被自动销毁
- 如果达到最大线程数,阻塞队列还是满的状态,那么将根据不同的拒绝策略对应处理
线程池有哪些参数?
1.corePoolSize(核心线程数):线程池维护的最小线程数。
2.maximumPoolSize(最大线程数):线程池最大线程数。
3.keepAliveTime:非核心线程空闲时存活的时间。
4.unit:keepAliveTime参数的时间单位。
5.workQueue:阻塞队列,用于存放待执行任务。
线程池的拒绝策略有哪些?
主要有4种拒绝策略:
- AbortPolicy(中止策略):线程池已满,新到的任务直接丢弃,抛出异常,这是默认策略
- CallerRunsPolicy(调用者运行策略): 该策略不会抛弃任务,也不会抛出异常,但是会将处理不过来的任务回退给调用者,由调用者来处理
- DiscardOldestPolicy(放弃最旧的策略):直接丢弃最旧任务
4.DiscardPolicy(放弃策略):直接丢弃当前最新任务
线程的生命周期
当线程被创建并启动以后,在线程的生命周期中,首先要经过新建(New)态,当调用start()方法后,会从新建态转换到就绪(Runnable)态,当拿到CPU的使用权就会从就绪态转换到运行(Running)态,当调用yield()方法或者失去CPU使用权的时候会从运行态转换到就绪态,调用sleep()方法 或者IO阻塞、等待同步锁、等待通知就会从运行态转换到阻塞(Blocked)态,sleep()时间到或者获得同步锁、IO方法返回、收到通知就会从阻塞态转换到就绪态。
调用stop()方法或者报错(Error)。抛出异常(exception)、run()/call()方法执行完成就会从运行态转换到死亡态。