文章目录
- 线程通讯
- **线程的状态**
- 进程之间的通信方式
- 线程之间的通信方式
- wait与sleep
- synchronized 与lock
- 线程池
- 线程池优点
- **线程池的创建方式**
- 线程池的七大参数
- 线程池的5种拒绝策略·
线程通讯
线程的状态
- 新建
- 就绪
- 运行
- 阻塞
- 等待和超时等待
- 中止
进程之间的通信方式
- 管道:是一种半双工的通信方式:数据只能单向流动,而且只能在具有亲缘关系的进程之间通信。(进程的亲缘关系通常是指父子进程关系)
- 命名管道:半双工的通信方式,允许无亲缘关系进程间的通信
- 消息队列:消息队列是消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息多少,管道只能继承无格式字节流以及缓冲区大小受限等特点。
- 共享存储:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建但多个进程都可以访问
- 信号量:是一个计数器,可以用来控制多个进程对共享资源的访问,他常用来作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源因。主要作为进程间以及统一进层不同线程之间的同步手段。
- 套接字Socket:套接口也是一种进程间通信机制,他可用于不同机器间的进程通信
- 信号:是进程间通信机制唯一的异步通信机制。
线程之间的通信方式
- 锁机制
- 信号量机制:包括无名线程信号和命名线程信号
- 信号机制
wait与sleep
wait和sleep都是让线程进入休眠状态
在执行的过程中都可以接收到终止线程执行的通知
wait方法 永久等待,所以必须先加锁
唤醒操作也需要加锁
wait和notify在配合使用时,一定要使用同一把锁
notify 唤醒线程 (多线程时,随机唤醒一个线程):
如何指定:LockSupport park()/unpark(线程)
park:让线程进行休眠
unpake:(线程名)
wait不传递参数时:进入waiting状态(其底层实现也是调用了wait(0)这个方法;
传递大于0的参数时,进入time_waiting状态
传0的时候,进入waiting状态
sleep和wait的区别
- wait执行的时候会释放锁,sleep执行时不会释放
- wait使用必须配合synchronized一起使用,而sleep不用
- wait是Object的方法,而sleep是Thread的方法
- 默认情况下wait进入waiting状态,而sleep会进入timed_waiting状态
- 使用wait时可以主动的唤醒进程,而sleep不能
sleep(0)和wait(0)有什么区别
- sleep表示过0毫秒之后继续执行,而wait表示一直休眠
- sleep(0)表示重新触发一次CPU竞争,
为什么wait会释放锁,而sleep不会释放锁?
- sleep必须传入一个最大等待时间,也就是说sleep是可控的(对于时间层面来讲),而wait不传递参数。从设计层面讲如果wait这个没有超时等待·时间的机制不释放锁的话,那么线程可能会一直阻塞,而sleep不存在这个问题
为什么wait是object的方法,而sleep是Thread的方法?
- wait需要操作锁,而锁是属于‘对象级别(所有的锁都是放在对象头里面)。它不是线程级别。一个线程中可以拥有多把锁,为了灵活期间,所以将wait放在Object当中
synchronized 与lock
synchronized 与 lock的区别
- synchronized是java关键字,在jvm层面时间加锁和解锁:Lock是一个接口,在代码层面实现加锁和解锁
- synchronized可以用在代码块上,方法上。lock只能写在代码里
- synchronized在代码执行完成或者出现异常时自动释放锁:Lock不会自动释放锁:需要在finally中显示释放锁
- synchronized会导致线程拿不到锁一直等待:Lock可以设置获取锁失败的超时时间
- synchronized无法知道是否获取锁成功:Lock可以通过trylock得知加锁是否成功
- synchronized锁可重入,不可中断,非公平;lock锁可重入,可中断,可公平/不公平,并且可以细分读写锁以提高效率
线程池
线程池的两个重要参数
1,线程
2,工作队列
线程池优点
线程缺点
- 线程创建他会开辟本地方法栈,虚拟机栈,程序计数器等线程私有的内存对象,同时销毁的时候需要销毁以上三个区域,因此频繁的创建和消耗比较消耗系统资源;
- 在任务量特别大的时候,并不能友好的拒绝任务
线程池:使用池化技术来管理线程和使用线程的方式
线程池优点
- 可以避免频繁的创建和消耗线程
- 可以更好的管理线程的个数和资源的个数
- 拥有更多的功能,比如线程池可以进行定时任务的执行·
- 线程池可以更优化的拒绝不能处理的任务
线程池的创建方式
- 创建固定个数的线程池
- 创建带缓存的线程池(短期有大量任务时时候使用)
- 创建执行定时任务的线程池
scheduleAtFixedRate:以上次任务的开始时间作为下一次任务的开始时间的
scheduleWithFixedDelay:以上次任务的结束时间作为下一次任务的开始时间的 - 创建单线程执行定时任务的线程池
- 创建单个线程的线程池
经典面试题:意义何在?
1 可以避免频繁创建和消耗线程带来的性能开销;
2 有任务队列可以存储多余的任务;
3 当有大量的任务不能处理的时候可以有好的执行拒绝策略
4 可以更好的管理和分配任务
- 根据当前的硬件的CPU生成对应个数的线程池,并且是异步执行。
- 最原始方式创建ThreadPoolExecutor
前六种线程池可能存在问题
线程数量不可控 —>OOM
工作任务队列不可控 —>OOM
线程池的七大参数
- 核心线程数(正式员工的数量)
- 最大线程数(正式员工和临时工)
- 存活时间(临时工生存时间)
- 时间单位
- 任务队列(一定要初始化大小)
- 线程工厂(设置线程池)
- 拒绝策略
线程池的5种拒绝策略·
- 默认拒绝策略(不执行新任务,抛出异常)
- 将新任务交给主线程执行
- 丢弃当前任务(当前任务+新任务)
- 丢弃老任务
- 自定义拒绝策略
ThreadLocal
set :将线程存储到ThreadLocal中
get:从线程中取私有变量
remove:移除私有变量