线程
一个进程有多个线程
代码并发执行,每个分支就是一个线程
场景:
某个请求需要a,b.c 3个互不相干的操作来实现,基于木桶原理,可以考虑使用线程来提高效率,
如果a b 只需要1ms,而c需要30ms,使用多线程30ms 比不使用多线程的32ms,
不考虑线程调度本身的时间(2~3ms)只提升了2ms,带来的却是程序复杂度提升,这种场景其实并不值得
demo:G:\project\demo\basic\Thread
Thread
定义
实现线程的类
方法
Thread.sleep
当前线程睡眠ms数,时间到了自动唤醒该线程,期间线程仍然持有对象锁,不考虑线程的优先级
wait
一定在synchronized里面,拿到我这个当前对象锁的线程停止,期间线程不持有该对象锁,可通过notify()唤醒
notify
叫醒一个现在正在wait在我的对象上的线程。
notify
叫醒所有现在正在wait在我的对象上的线程(不能叫醒自己)。
yield
当前Thread 让出CPU给其他线程执行,只会给相同优先级或更高优先级的线程以运行的机会;
join
调用该方法的线程对象合入某个线程or合入主程序
getPriority
获取当前线程优先级
setPriority
设置当前线程优先级
synchronized
方法锁和对象锁都是锁定当前的对象
区别在于:
访问同一个对象锁对象是一定同步
线程1访问对象1的对象锁方法,线程2也能异步访问对象1的非对象锁方法
线程的生命周期
就绪状态
执行start()方法时,该线程进入就绪状态.
运行状态
cpu调度资源给你,线程进入运行状态.
阻塞状态
阻塞事件出现,线程进入阻塞状态
阻塞事件
1.sleep()
2.调用阻塞时的IO方法
终止
线程执行完毕.
线程同步
两个线程调用同一个对象资源时,需要加锁来确保线程安全.
否则就会导致线程之间执行代码产生影响出错
死锁
两个线程内部同一时间需要获取对方的对象锁才能继续执行,这时候就是死锁。
![线程声明周期](https://i-blog.csdnimg.cn/blog_migrate/aff17759f0dd939aa37b3538c0dc08c8.png)
线程池
定义
管理线程的创建销毁的类ThreadPoolExecutor
多例模式,多个线程对象供使用者调用
用完返回线程池
减少线程创建销毁的开销
源码
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,
TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,
RejectedExecutionHandler handler)
属性
corePoolSize:核心线程数量:不会被回收
maximumPoolSize:线程池中可以容纳的最大线程的数量
keepAliveTime:除了核心线程之外的其他的最长可以保留的时间
unit:计算keepAliveTime时间的一个单位
workQueue:任务可以储存在任务队列中等待被执行,执行的是FIFIO原则(先进先出)
threadFactory:创建线程的线程工厂
handler:是一种拒绝策略,我们可以在任务满了的情况下,拒绝执行某些任务。
工作流程
任务进来时,首先执行判断,判断核心线程是否处于空闲状态,
如果不是,核心线程就先就执行任务,如果核心线程已满,则判断任务队列是否有地方存放该任务,
若果有,就将任务保存在任务队列中,等待执行,
如果满了,在判断最大可容纳的线程数,
如果没有超出这个数量,就开创非核心线程执行任务,如果超出了,就调用handler实现拒绝策略。
好处
第一
降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二
提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三
提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,
使用线程池可以进行统一分配、调优和监控。但是,要做到合理利用线程池,必须对其实现原理了如指掌
悲观锁乐观锁
悲观锁
很悲观,认为什么时候都会出同步问题,任何操作都加锁
乐观锁
很乐观,认为什么时候都不会出同步问题,如果数据没修改,就不加锁
1