为什么不直接调用run方法而是调用start方法?
start方法会先创建一条线程,再用创建出的新线程去执行对应的run方法,这样才是起到多线程效果,如果直接调用run方法,则只是在原线程执行。
线程的sleep方法和wait方法的区别?
首先这两个方法都是让当前线程暂停执行一段时间,sleep方法属于Thread类的静态方法,让当前线程暂停执行,但不释放对象锁,到指定时间自动唤醒,通常用于简单的暂停操作,不涉及对象状态变更;wait方法是Object类的方法,必须在同步代码块或同步方法中调用,暂停时会释放当前线程持有的锁,需要调用notify或者notifyAll方法唤醒,通常用于线程间的通信,等待某个条件的发生。
什么是乐观锁和悲观锁?
悲观锁: 悲观锁在操作数据时比较悲观,认为别人会同时修改数据,因此操作数据时会把数据锁住,直到操作完才会释放锁;
乐观锁: 乐观锁在操作数据时非常乐观,认为别人不会同时修改数据,乐观锁不会上锁,只是在执行更新操作的时候判断一下数据有没有被修改,被修改则放弃操作,否则执行操作。
什么是CAS?
CompareAndSwap,比较与交换,主要是通过处理器的指令来保证操作的原子性,cas指令包含3个参数,共享变量内存地址的值v、预期值A以及要修改的新值B,当内存地址值与预期值相等时,才把内存地址值更新为新值B,否则不做任何操作。
说说你对原子性、可见性、有序性的理解?
原子性:是指一个操作是不可分割、不可中断的,要么全部执行并且不被打断,要么就都不执行,synchronized可以保证原子性;
可见性:是指一个线程修改了某一共享变量的值时,其他线程能够立即知道这个修改,volatile、final、synchronized可以保证可见性;
有序性:是指对于一个线程的执行代码,从前往后依次执行,单线程下可以认为程序是有序的,并发情况可能会发生指令重排序,volatile、synchronized可以保证有序性。
synchronized加锁维度?
修饰实例方法: 相当于当前对象实例加锁
修饰静态方法: 给当前类加锁
修饰代码块: this对象实例加锁 xxx.class给类加锁
对死锁的了解及避免方案?
死锁是指两个或两个以上的线程在执行过程中,因竞争资源而造成互相等待、互相阻塞的现象,在无外力作用的情况下,这些线程将一直阻塞下去
死锁的产生必须具备四个条件:
互斥使用: 资源只能同时只由一个线程占用,如果此时还有其他线程请求获取该资源,需要等待占有资源线程释放该资源;
请求与保持: 资源请求者在请求其他资源的同时,不会释放已占有资源;
不可抢占: 资源请求者不能强行从其他线程抢占资源,只能由资源持有者主动释放资源;
循环等待: 两个或两个以上线程在占用自己资源同时,相互抢占对方资源从而相互等待对方释放资源。
避免死锁方法:
破坏请求与保持: 一次性获取全部的资源;
破坏不可抢占: 线程请求资源时,如果申请失败,主动释放自己占有资源;
破坏循环等待: 按顺序申请资源,避免环路申请资源。
线程有哪些状态?
NEW(新建状态): Thread线程对象已经创建,但尚未调用start方法创建线程;
RUNNABLE(可运行状态): 调用start方法进入已就绪状态,该状态的线程随时可以调度运行或者已经在CPU上运行;
BLOCKED(阻塞状态): 由锁竞争引起的阻塞状态,给多个线程加上同一个锁,当有一个线程拿到锁后,剩下的线程就进入阻塞状态;
WAITING(不限时等待状态): 线程无限期的等待某个条件发生,比如调用另一线程不带参数的join方法等待对方执行完成或者调用wait方法等待;
TIMED_WAITING(限时等待状态): 有时间限制的阻塞等待,比如使用带参数的join或wait方法;
TERMINATED(终止状态): 线程执行完毕或者因异常退出run方法后,线程结束生命周期。
线程池有哪些状态?
RUNNING: 线程处于运行状态,可以接收新任务,也会处理等待队列中的任务;
SHUTDOWN: 表示线程池不再接收新任务,但会继续执行已经提交的任务(包括队列中的任务),RUNNING状态调用shutdown方法进入SHUTDOWN状态;
STOP: 表示线程池不再接收新任务,并且会尝试中断正在执行的任务,同时清空任务队列,RUNNING状态调用shutdownNow方法进入STOP状态;
TIDYING: 表示线程池的所有任务都已终止,工作线程数量为0,线程池即将进入TERMINATED状态,当SHUTDOWN状态任务队列为空,且所有任务执行完毕或者STOP状态任务队列为空,所有任务都
已终止时会进入TIDYING状态;
TERMINATED: 表示线程池已经彻底关闭,所有任务都已完成,所有工作线程都已销毁,TIDYING状态时调用terminated方法执行完毕进入TERMINATED状态。
线程池的工作流程?
刚创建时,线程池里是没有线程的,当调用execute方法添加一个任务时,会判断
a,如果正在运行的线程数量小于corePoolsize(核心线程数),就会创建线程并执行这个任务;
b.如果正在运行的线程数量大于或等于corePoolsize(核心线程数),就会把这个任务放入队列;
c.如果这个时候队列满了,而且正在运行的线程数量小于maximumPoolSize(最大线程数),就会创建非核心线程并执行这个任务;
d.如果这个时候队列满了,而且正在运行的线程数量大于或等于maximumPoolSize(最大线程数),就会根据配置的拒绝策略来处理任务;
当一个线程执行完任务,就会从队列里取下一个任务来执行,当一个线程无事可做,超keepAliveTime(空闲线程存活时间),线程池会判断当前运行的线程数量是否大于corePoolsize(核心线程数),如果大于则停掉线程,最终恢复到corePoolsize(核心线程)。
线程池有哪些拒绝策略?
AbortPolicy: 默认策略,直接抛出异常
CallerRunsPolicy: 用调用者所在的线程来执行任务
DiscardoldestPolicy: 丢弃队列里时间最早的任务,也就是即将执行的任务
DiscardPolicy: 当前任务直接丢弃,不做任何处理
线程池怎么接收异常?
try catch捕获异常
submit执行,future.get()接收异常
重写ThreadPoolExecutor.afterExecute方法处理接收的异常
更多内容正在更新中…