高级会员
- 威望
- 371
- 贡献
- 478
- 热心值
- 0
- 金币
- 19
- 注册时间
- 2020-3-29
|
1. 进程和线程的区别?
• 进程:进程是资源分配的最小单位。一个进程可以拥有多个线程;
• 线程:线程是进程执行的最小单位;线程是进程中的一个任务;一个线程只能属于一个进程;
2. 讲下线程安全产生的原因?
• 多个线程操作同一个数据;
• 操作共享数据的代码有多条。
3. 同步与异步的区别?
• 同步:
○ 发送一个请求,需要等待返回,然后再发送下一个请求;
○ 同步可以避免出现死锁,读脏数据的发生;
• 异步:
○ 发送一个请求,无需等待返回,随时可以再发送下一个请求;
○ 异步可以提高效率,但是并发情况下容易出现线程安全问题;
• 同步和异步的最大区别在于:同步需要等待,异步不需要。
4. Thread与Runnable的区别?
• Thread通过继承的方式,会有单继承的局限性,Runnable是通过实现接口的方式,解决了单继承的局限性
• Thread底层也是实现了Runnable接口
5. Runnable与Callable的区别?
• Callable规定的方法是call(),Runnable规定的方法是run();
• Callable任务执行完成后可以返回值,而Runnable的任务是不能返回值的;
• Call()方法可以抛出异常,run()方法不可以。
6. 线程有哪些状态?是怎么转换的?
• New(新建):新建线程之后进入该状态
• Runnable(运行):新建的线程调用start方法以及阻塞与等待的方法结束阻塞与等待的时候,并且抢占到了CPU资源,进入运行状态,没有抢占到CPU资源的话会进入就绪状态
• Blocked(阻塞):调用sleep方法或者wait方法时,会让当前线程阻塞
• TIMED_WAITTING(有限等待):调用sleep方法的时候
• TERMINATED(终止):run方法结束
7. Java并发sleep与wait,notify与notifyAll的区别?
• wait,notify,notifyAll都是Object类的方法,sleep是Thread类的方法
• wait方法的意思是持有该锁对象的线程释放锁,进入wait状态
• sleep方法的作用是将当前线程暂停一定的时间,但在这期间并不释放锁
• notify()用于随机唤醒一个等待该锁对象的线程
• notifyAll()用于唤醒所有等待该锁对象的线程
8. 有多少种方法可以让线程阻塞?
• Thread.sleep (long millis)方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。
• Object类中的wait()方法,导致当前的线程等待,直到其他线程调用此对象的 notify() 唤醒方法。这个两个唤醒方法也是Object类中的方法,行为等价于调用 wait() 一样。wait() 和 notify() 方法:两个方法配套使用,wait() 使得线程进入阻塞状态,它有两种形式,一种允许 指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify() 被调用.
• Thread.yield() 方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。yield() 使得线程放弃当前分得的 CPU 时间,但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程.
• join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
9. 线程方法中的异常如何处理?副线程可以捕获到吗?
• 在线程run方法中直接进行try…catch(可以捕获到副线程的异常)
• 为线程设置异常处理器UncaughtExceptionHandler(可以捕获到副线程的异常)
• 通过Future的get方法捕获异常
10. 简述线程池原理?
所谓线程池本质是一个HashSet。多余的任务会放在阻塞队列中。 只有当阻塞队列满了后,才会触发非核心线程的创建。所以非核心线程只是临时过来打杂的。直到空闲了,然后自己关闭了。 线程池原理关键技术:锁(lock,cas)、阻塞队列、hashSet(资源池)
11. 无界队列真的无界吗?
不是,也有最大容量限制,Integer.MAX_VALUE。
12. 线程池的优势和作用?
• 降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;
• 提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行;
• 方便线程并发数的管控。因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成cpu过度切换(cpu切换线程是有时间成本的(需要保持当前执行线程的现场,并恢复要执行线程的现场))
• 提供更强大的功能,延时定时线程池。
13. Java有哪几种内置线程池?每种线程池的区别?
• newCachedThreadPool:用来创建一个可以无限扩大的线程池,适用于负载较轻的场景,执行短期异步任务。(可以使得任务快速得到执行,因为任务时间执行短,可以很快结束,也不会造成cpu过度切换)
• newFixedThreadPool:创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化,适用于负载较重的场景,对当前线程数量进行限制。(保证线程数可控,不会造成线程过多,导致系统负载更为严重)
• newSingleThreadExecutor:创建一个单线程的线程池,适用于需要保证顺序执行各个任务。
• newScheduledThreadPool:适用于执行延时或者周期性任务。
14. FixedThreadPool用的阻塞队列是什么?
LinkedBlockingQueue
15. 线程池中的几种重要的参数及流程说明?
• 核心线程数:当向线程池提交一个任务时,若线程池已创建的线程数小于corePoolSize,即便此时存在空闲线程,也会通过创建一个新线程来执行该任务,直到已创建的线程数大于或等于corePoolSize时;
• 最大线程数:线程池所允许的最大线程个数。当队列满了,且已创建的线程数小于maximumPoolSize,则线程池会创建新的线程来执行任务。另外,对于无界队列,可忽略该参数;
• 线程存活保持时间:当线程池中线程数大于核心线程数时,线程的空闲时间如果超过线程存活时间,那么这个线程就会被销毁,直到线程池中的线程数小于等于核心线程数;
• 任务队列:用于传输和保存等待执行任务的阻塞队列;
• 线程工厂:用于创建新线程。threadFactory创建的线程也是采用new Thread()方式,threadFactory创建的线程名都具有统一的风格:pool-m-thread-n(m为线程池的编号,n为线程池内的线程编号);
• 拒绝策略:当线程池和队列都满了,再加入线程会执行此策略。
流程:
1、判断线程池中当前线程数是否大于核心线程数,如果小于,在创建一个新的线程来执行任务
2、如果大于则判断任务队列是否已满,没满则将新提交的任务添加在工作队列
3、已满则判断线程池中当前线程数是否大于最大线程数,如果小于,则创建一个新的线程来执行任务,如果大于,则执行饱和策略。
|
|