线程:
1、线程是什么?
线程是操作系统中最小的计算(工作)单元
2、多线程是什么,为什么要用多线程?
为了提升程序的处理能力的一种线程设计,叫多线程;第一为了迎合当代多核心cpu 的发展,多线程能提升cpu 的利用率,第二提升系统的吞吐量,处理速度,从而提升软件的用户体验,
第三更好的编程,已经制定了一套多线程的编程规范,开发者只需要关心业务。
3、线程的状态有多少种,都是怎么扭转的?
线程有6种状态,分别是:
new 初始状态:创建时的状态
Runnable运行状态(java 将 Runnable、running、ready 状态统称为 Runnable状态):运行start() 方法后的状态
BLocked阻塞状态:进入Synchronized 修饰的同步方法或者同步代码块后的状态
waiting 等待状态:调用Wait(),join() 方法后的状态,wait状态会释放对象的锁
time_waiting 超时等待状态:调用wait(long) 方法,调用join(long) 方法,调用Thread.sleep(long) 方法都会让线程进入该状态,超时后会自行返回
terminated 终止状态:表示当前线程已经执行完毕
4、 什么是deamon线程,作用是什么?
守护线程
5、如何启动线程和终止线程 ?
调用Start() 方法启动线程,终止线程有stop方法,但不建议使用,因为不能保证线程锁持有的资源会释放,安全的终止线程可调用cancel() 方法。
6、线程通信,多线程情况下如何保证线程安全?
1、volatile 保证线程对共享变量访问的可见性, 线程在写volatile变量后要及时写回主存中,并通知其他volatile读线程失效本地的副本变量;为了实现volatile 变量保证内存可见性,jmm 采用了防止重排序策略,实现防止指令重排就是采用插入内存屏障,storestore:保证写–写顺序执行;storeload:保证写–读顺序执行;loadload:保证读–读顺序执行,
loadstore:保证读–写顺序执行
2、synchronized 保证一个被修饰方法或者一块被修饰的代码块在同一时间内只能由一个线程执行,但方法和代码块的实现有所不同,方法是通过给方法添加ACC_SYNCHRONIZED
标签,而代码块是通过获取 monitor(监视器) 排他对象来实现的,排他指的是只能有一个线程获取,synchronized 修饰的对象监视器,当有多个线程需要执行被synchronized 修饰
的代码块时,就需要竞争monitor对象,获取到的线程去执行,没有获取到锁的线程进入Blocked(阻塞) 状态,并在synchronizedqueue 同步队列中,等获取到monitor 对象的线程
执行到monitorExit 指令,在唤醒队列中的线程,让他们再次竞争获取monitor 对象。
7、线程的等待和通知机制
1、等待/通知方法,notify() 方法:通知一个对象上处于waiting状态的等待的线程,对象上有一个等待队列;notifyall()方法:通知等待队列中的所有线程,并将线程迁移
至synchronizedQueue 同步队列;wait()方法:使线程进入waiting状态,进入waiting 状态的线程要释放对象的锁;wait(long) 方法:使线程等待一段时间后自行返回。
8、Thread.join()方法
join 方法使线程进入Waiting 状态,等待前面的线程执行完后,调用notifyAll 方法唤醒所有等待在该线程对象上的线程。
9、ThreadLocal的使用
是一个线程上的变量,一个以ThreadLocal 为key ,任意对象为值的存储结构。
线程池:
1、线程池的作用:
1、降低资源消耗(无需重复的创建线程与销毁线程,创建线程和销毁线程会有一定的资源消耗)
2、提高响应速度(已有创建好的线程,就可以直接使用,节省了一部分的线程创建带来的时间消耗)
3、提高了线程可管理性( 已经定义好了最多有多少个线程,不会无限创建)
2、创建线程池的参数有几个,分别是什么?
有7个,分别是:
1、corePoolSize :核心线程数
2、maximumPoolSize:最大线程数
3、keepAliveTime:空闲线程存活时间
4、TimeUnit:空闲线程存活时间单位
5、runnableTaskQueue:任务队列:
ArrayBLockingQueue 数组结构的有界阻塞队列
LinkedBlockingQueue 链表结构的阻塞队列,吞吐量高于前者
SynchronizedQueue 不存储任务的元素的同步阻塞队列,吞吐量高于前者
PriorityBlockingQueue 有优先级的无限阻塞队列,吞吐量高于前者(不建议使用)
6、RejectedExecutionHandler:饱和策略------>>“直接丢弃任务”;“抛出异常”,“使用调用者线程执行任务”;“删除队列中最近的一个任务,执行当前任务”
7、ThreadFactory:创建线程的工厂,用guave 的ThreadBuilder 能快速为线程起名字
3、线程池处理任务的过程
当有任务提交过来,线程池会先检查worker 的数量是否大于核心线程数量,如果大于,则将当前任务方如任务队列中,如果任务队列也满了,则将会判断当前的worker
数是否大于最大线程数,没有大于则创建线程来执行,如果大于则要走饱和策略,根据设置的饱和策略进行处理
4、如何配置线程池
需要权衡线程池用的地方是io 密集型的处理,还是计算密集型的处理,如果是io密集型,则可以设置线程数为 2* Cpu核心数,计算密集型,则可以设置Cpu个数+1 个线程数
获取Cpu核数可以通过:Runtime.getRuntime().availiableProcessors()