多线程相关问题

怎么创建线程?

线程池问题

wait 和 sleep 的区别和联系

wait是Object方法。 sleep是T和read的方法

参数详解

corePoolSize 核心线程优先使用;默认创建线程池时线程不会立即启动,直到有任务提交才开始启动线程并逐渐时线程数目达到corePoolSize。
maximumPoolSize-池中允许的最大线程数。需要注意的是当核心线程满阻塞队列也满时才会判断当前线程数是否小于最大线程数,并决定是否创建新线程。
keepAliveTime - 当线程数大于核心时,多于的空闲线程最多存活时间
unit - keepAliveTime参数的时间单位
workQueue - 当线程数目超过核心线程数时用于保存任务的队列;
工作线程的三种策略:
有界 ArrayBlockingQueue(当任务耗时较长时会导致新任务在队列中堆积导致OOM)
无界 LinkedBlockingQueue
同步移交队列(线程移交的机制);此队列仅保存实现Runnable接口的任务
threadFactory - 执行程序创建新线程时使用的工厂。
handler - 阻塞队列已满且线程数达到最大值时所采取的饱和策略。java默认提供了4种饱和策略的实现方式:中止、抛弃、抛弃最旧的、调用者运行。将在下文中详细阐述。

什么是阻塞队列?

阻塞队列就是当核心线程数满了,进入到工作线程(workQueue )中的数量。

饱和策略RejectedExecutionHandler

4种策略都做为静态内部类在ThreadPoolExcutor中进行实现
1,饱和时会抛出RejectedExecutionException(继承自RuntimeException),调用者可捕获该异常自行处理
2,不做任何处理直接抛弃任务
3,抛弃旧任务,阻塞队列中的头元素出队抛弃,再尝试提交任务。如果此时阻塞队列使用PriorityBlockingQueue优先级队列,将会导致优先级最高的任务被抛弃,因此不建议将该种策略配合优先级队列使用。
4,将任务回退给调用者来直接运行

  • – Java提供的四种常用线程池解析不建议使用不做解析 —
    强制ThreadPoolExecutor创建】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明: Executors 返回的线程池对象的弊端如下:
    1) FixedThreadPool 和 SingleThreadPool : 允许的请求队列长度为 Integer.MAX_VALUE ,可能会堆积大量的请求,从而导致 OOM 。
    2) CachedThreadPool 和 ScheduledThreadPool : 允许的创建线程数量为 Integer.MAX_VALUE ,可能会创建大量的线程,从而导致 OOM

顺序流程

总结

1 如果核心线程还有剩余,先创建核心线程
2 核心线程满了,工作队列还有剩余 线程会阻塞到工作队列
3 核心线程和工作队列都满了,并且还没有达到最大线程,则创建并启动一个线程来执行新提交的任务,可能会导致内存资源被耗尽CPU飙升。
4 如果 核心线程已满&工作队列已满&工作线程>=最大线程数。则根据拒绝策略来处理任务,默认的处理方式是直接丢弃任务并抛出异常。
5 线程池一般建议maximumPoolSize和corePoolSize设置成一样,当工作队列存满了之后,交给拒绝策略去处理,避免宕机;

ConcurrentHashMap 底层原理

jdk1.7
内部主要是一个Segment数组,而数组的每一项又是HashEntry数组,元素存在HashEntry中。每次锁定的是Segment对象,也就是整个 HashEntry 数组又叫分段锁。
jdk1.8
舍弃分段锁实现方式,元素存在 node数组中,每次锁住的是一个Node对象,而不是某一段数组,所以支持写的高并发, 再者他引入红黑树在hash冲突严重时,读操作的效率更高。

为什么红黑数hash冲突效率高

volatile 的三特性

volatile是什么?怎么理解
可见性: volatile 修饰的变量在被修改后可以立即同步到主内存中,被修饰的变量在每次用之前都是从主内存刷新。本质也是通过内存屏障来实现,写内存屏障可以促使处理器将当前存储缓存(store buffer)的值写回主内存,读内存屏障可以促使处理器处理失效队列,进而避免存储缓存和失效队列的非实时性带来的问题;
不保证原子性:(这就是为什么叫轻量级同步机制)
有序性(禁止指令重排): volatile通过内存屏障来禁止指令重排;
每个写操作前插入一个storestore 屏障,写之后插入 storeload屏障
每个读操作前插入一个loadload屏障,读之后插入 loadstore屏障

描述一下锁的四种状态及升级过程?

synchronized锁的膨胀过程:
当线程访问同步代码块。首先查看当前锁状态是否是偏向锁(可偏向状态)
1、如果是偏向锁:
1.1、检查当前mark word中记录是否是当前线程id,如果是当前线程id,则获得偏向锁执行同步代码
块。
1.2、如果不是当前线程id,cas操作替换线程id,替换成功获得偏向锁(线程复用),替换失败锁撤销升
级轻量锁(同一类对象多次撤销升级达到阈值20,则批量重偏向,这个点可以稍微提一下,详见下面的注意)
2、升级轻量锁
升级轻量锁对于当前线程,分配栈帧锁记录lock_record(包含mark word和object-指向锁记录首地
址),对象头mark word复制到线程栈帧的锁记录 mark word存储的是无锁的hashcode(里面有重入次数
问题)
3、重量级锁(纯理论可结合源码)
CAS自旋达到一定次数升级为重量级锁(多个线程同时竞争锁时)
存储在ObjectMonitor对象,里面有很多属性ContentionList、EntryList 、WaitSet、
owner。当一个线程尝试获取锁时,如果该锁已经被占用,则该线程封装成ObjectWaiter对象插到
ContentionList队列的对首,然后调用park挂起。该线程锁时方式会从ContentionList或EntryList挑
一个唤醒。线程获得锁后调用Object的wait方法,则会加入到WaitSet集合中(当前锁或膨胀为重量级锁)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值