1.线程的五个状态
创建、就绪、运行、阻塞、终止
2.start之后并不一定是立即执行,代表的是就绪状态;
3.阻塞状态: 阻塞状态是正在运行的线程由于某种原因放弃cpu的使用权,进入就绪状态;
有三种类型:
①运行的线程执行wait方法,线程被jvm放入等待池中;
②运行的线程获取同步锁时,该同步锁被别的线程占用,线程被jvm放入同步锁中;
③运行的线程执行sleep方法或join方法时,等睡眠时间超时的时候,join()等待线程,重新进入就绪状态;
4.sleep() 线程睡眠,在睡眠超时之后进入就绪状态,并不会释放锁;
wait():执行此方法时,当前线程暂停执行,直到其他线程调用此方法的notifyI()唤醒;
join():执行此方法时,当前线程暂停,让执行此方法的线程运行完之后,在进入就绪状态;
yield() :执行此方法时,将让给优先级更高或者同级的线程;让当前运行状态回到可运行状态;
notify():
5.sleep()和yield()的区别
sleep()之后线程进入阻塞状态直到超时,把机会让给了其他线程
而yield()让步是进入就绪状态,是把机会给了同等优先级或者更高优先级的线程,自己也有可能再次被选中。
6.sleep()和wait()的区别
wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
在等待时 wait 会释放锁,而 sleep 一直持有锁。Wait 通常被用于线程间交互,sleep 通常被用于暂停执行;’
7.wait ()、notify()必须在synchronized(Obj)一起使用,针对的是已经获取到锁的来进行等待操作,从功能上来说,使当前线程释放锁,同时让该线程处于等待,一直到被唤醒,才能继续获取锁;注意 :执行notify的时候,并不是立刻执行被唤醒,而是当前锁内程序执行完后,从wait线程锁中随机找一线程对其解锁;
8. 线程池
线程池执行流程:
任务过来之后,查看核心线程是否有空闲的,有则执行。
没有,则查看等待队列是否满了,如果不满则插入队列等待。
满了,则判断最大可容线程数没有超过最大值,则开创非核心线程执行任务,则handle调用实现拒绝策略,
拒绝策略有四种:
不执行抛出异常,线程池已经满了;
不执行也不抛出异常;
将消息队列中的第一个替代为当前线程;
直接用excute进行执行当前任务;
常见的四种线程:
CacheThreadPool : 可缓存线程池,有核心线程,也有非核心线程(数量为没有上线),有任务就处理,没有任务就收回线程,适用于耗时少 任务量大的线程。 缺点创建线程数量多
singThreadPool:只有一个线程,使用户有顺序执行的场景。缺点是:队列堆积,消耗内存
FixedThreadPool:定长线程池,没有非核心线程池,定长的,可控制线程最大并发数,超出的线程会在队列中等待。缺点是:队列堆积,消耗内存
SecudleThreadPool: 周期性线程池,按照某种特定的计划周期执行,非核心线程无线。缺点创建线程数量多
使用线程的好处:
节省资源;通过重复利用已经建立好的线程,节省了创建线程的资源消耗
提高响应速度;当任务来临时,不必等线程创建,可以立即执行。
便于管理:使用线程池统一管理线程。
execute和submit的区别?
都是用来执行任务,但是submit有返回值
线程池都有哪几种工作队列
数组有界队列:原则是对元素进行排序
链表结构的阻塞队列:先进先出。
一个不存储元素的阻塞队列。只有移除之后,后面的才可以进入,否则一直处于zuse
一个具有优先级的无限阻塞队列();
线程配置:
- CPU密集型任务
尽量使用较小的线程池,一般为CPU核心数+1。
因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,只能增加上下文切换的次数,因此会带来额外的开销。 - IO密集型任务
可以使用稍大的线程池,一般为2*CPU核心数。
IO密集型任务CPU使用率并不高,因此可以让CPU在等待IO的时候去处理别的任务,充分利用CPU时间。