JAVA线程和线程池

参考: https://blog.csdn.net/Evankaka/article/details/44153709
线程创建:
1\继承Thread类 (尽管Thread也是继承Runnable)
2\实现Runable接口
3\Callable
4\线程池(线程池属于Runable接口)
前两个重写run方法,使用start调用
继承Thread 直接调用start方法就行
实现Runable接口 要这么调用 new Thread(new RunnableImpl()).start();

继承Thread创建的线程是后台线程,主线程结束,后台线程就会自动结束;
(后台线程是指在程序运行的时候在后台提供的一种通用服务线程,并且这种线程并不属于程序中不可或缺的部分)

线程状态: java.lang.Thread.State
NEW(新建) RUNNABLE(运行), BLOCKED(阻塞), WAITING(等待),TIMED_WAITING(超时等待) TERMINATED(终止)
参考: https://my.oschina.net/goldenshaw?tab=newest&catalogId=3277710
https://blog.csdn.net/jackie_xiaonan/article/details/47907625
NEW(新建): 尚未启动的线程的线程状态----翻译来之百度

RUNNABLE(运行): 可运行线程的线程状态。可运行线程状态正在Java虚拟机中执行,但它可能正在等待操作系统中的其他资源 例如处理器。

BLOCKED(阻塞): (同步方法,同步锁的阻塞)实际上就是被synchronized方法或者synchronized代码块阻塞,阻塞是synchronized特有的
简单的来讲就是因为获取不到锁而发生的阻塞
Lock的实现是等待

WAITING(等待): 进入等待状态线程调用了俩方法:Object.wait, Thread.join,线程处于不再活动的状态,即是从调度队列中剔除
动作通常即是指“notify或是notifyAll”。

TIMED_WAITING(超时等待):
调用 Object.wait(xxx)
TIMED_WAITING 与 WAITING 间的联系还是很紧密的,主要差异在时限(timeout)
sleep 也是一种TIMED_WAITING 中的一种,但是无法使用notify唤醒,而且sleep 方法不会释放锁

TERMINATED(终止):
* Thread state for a terminated thread.
* The thread has completed execution.
线程已完成执行

简单的来讲就是:
在火车上, 你准备去厕所(这是新建),厕所里面有人,你在外面等着(这是阻塞),厕所里没人,你进去了(这是运行),
厕所没水了,列车员要给厕所加水,让你回去等(这是等待),你给列车员说,5分钟之后,没等到你通知我,我还会过来(这叫超时等待),
你上完厕所回来了(这是终止)

参考:
https://blog.csdn.net/xy3233/article/details/86661821

线程池:
为什么选线程池不是直接使用线程?
线程的创建和销毁是消耗时间的,使用线程池,则可以提高服务器性能

线程池种类:
(1)newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
(2)newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。(线程数量固定)
(3)newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
(4)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
其底层都是实现ThreadPoolExecutor,
然而,阿里编码规约上写:
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,
这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
原因: newCachedThreadPool(可缓存线程池)和newScheduledThreadPool(定长线程池) 线程最大数都是Integer.MAX_VALUE太耗内存
newFixedThreadPool和newSingleThreadExecutor 堆积的请求处理队列可能会耗费非常大的内存

ThreadPoolExecutor 构造参数
int corePoolSize: 核心池大小,意思是当超过这个范围的时候,就需要将新的线程放到等待队列中了即workQueue;
int maximumPoolSize: 线程池最大线程数量,表明线程池能创建的最大线程数
long keepAliveTime; 当活跃线程数大于核心线程数,空闲的多余线程最大存活时间。
TimeUnit unit: 存活时间的单位
BlockingQueue workQueue: 存放任务的队列—阻塞队列
ThreadFactory threadFactory, : 线程工厂,用来创建线程
RejectedExecutionHandler handler : 任务拒绝策略

线程池的执行流程,
1,线程池启动,线程池中没有线程运行
2,提交一个新的任务,在corePool中创建一个线程执行程序,再来一个再创建一个,无论第一个线程有没有执行完,直到线程corePool中的线程数量等于corePoolSize
3,继续提交任务,如果有空闲线程,就由空闲线程执行,如果corePool中的线程如果正在运行,就加入BlockingQueue(阻塞队列)中.
4,继续提交任务,如果BlockingQueue(阻塞队列)已满,则创建非corePool线程执行,直到达到maximumPoolSize线程池最大线程数,
5,继续提交任务,maximumPoolSize线程池最大线程数,已满,则执行RejectedExecutionHandler(任务拒绝策略)
6,当活跃线程数大于核心线程数,空闲的多余线程超过最大存活时间(keepAliveTime),多余的线程会被回收corePool中的线程不会被回收,。

阻塞队列 及阻塞策略:
workQueue的类型为BlockingQueue,通常可以取下面三种类型:
1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;
2)LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;
3)synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。

拒绝策略 RejectedExecutionHandler:
ThreadPoolExecutor.AbortPolicy: 丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 ,会阻塞入口

线程池状态:
ThreadPoolExecutor (386)
private static final int RUNNING = -1 << COUNT_BITS; 线程刚被创建,任务数为 0,能够接收新任务,对已排队的任务进行处理。
private static final int SHUTDOWN = 0 << COUNT_BITS; 不接收新任务,但能处理已排队的任务。调用线程池的 shutdown()方法,线程池由 RUNNING 转变为 SHUTDOWN 状态。
private static final int STOP = 1 << COUNT_BITS; 不接收新任务,不处理已排队的任务,并且会中断正在处理的任务。调用线程池的 shutdownNow() 方法
private static final int TIDYING = 2 << COUNT_BITS; 任务数为 0, 其他所有任务已终止
private static final int TERMINATED = 3 << COUNT_BITS; 线程池彻底终止。

ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown()和shutdownNow(),其中:
shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务 即 SHUTDOWN 状态
shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务 即 STOP 状态

如何定义线程池参数:
CPU密集型任务(计算密集型): 比如计算圆周率,内存,硬盘不需要参与或者参与较少,主要消耗CPU资源
IO密集型:IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成
CPU密集型: 线程池的大小推荐为CPU数量 + 1,CPU数量可以根据Runtime.availableProcessors方法获取,避免频繁上下文 切换
IO密集型: CPU数量 * CPU利用率 * (1 + 线程等待时间/线程CPU时间) 也有(参考值可以设置为2*NCPU )

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值