三、多线程面试题

  1. 并行和并发有什么区别?
    (1)并行:多个处理器或多核处理器同时处理多个任务。(是真正的物理上的同时发生)
    (2)并发:多个任务在同一个 CPU 核上,按细分的时间片轮流(交替)执行,从逻辑上来看
    那些任务是同时执行。(逻辑上的同时发生)
      举个例子:排队打饭,当只有一个窗口可以打饭的时候,我们排成了两排,那么这两排只能
    一边一个来,这就是并发;
          如果有两个窗口可以打饭的话,一个队一个窗口,那么这两排可以同时进行打饭,
    这就是并行了。

     

  2. 线程和进程的区别?
        首先一个程序下至少有一个进程,一个进程下至少有一个线程,
        一个进程下也可以有多个线程来增加程序的执行速度。
    
      线程是运行调度的最小单位;进程是资源调度的最小单位。
    
      进程在执行过程中拥有独立的内存单元,而多个线程共享内存。

     

  3. 守护线程是什么?
    (1)守护线程是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务
    或等待处理某些发生的事件。在 Java 中垃圾回收线程就是特殊的守护线程。
    
    (2)守护线程(即daemon thread),是个服务线程,准确地来说就是服务其他的线程,这
    是它的作用——而其他的线程只有一种,那就是用户线程。所以java里线程分2种,
        1、守护线程,比如垃圾回收线程,就是最典型的守护线程。
        2、用户线程,就是应用程序里的自定义线程。

     

  4. 创建线程有哪几种方式?
    (1)继承Thread类创建线程类
    (2)通过Runnable接口创建线程类
    (3)通过Callable和Future创建线程

     

  5. 说一下 runnable 和 callable 有什么区别?
    (1)相同点: 都是接口
                都可以编写多线程程序
                都采用Thread.start()启动线程
    
    (2)不同点: Runnable没有返回值;Callable可以返回执行结果,是个泛型,和Future、
    FutureTask配合可以用来获取异步执行的结果;Callable接口的call()方法允许抛出异常;
    Runnable的run()方法异常只能在内部消化,不能往上继续抛。
    
    注:Callalbe接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主
    进程的继续往下执行,如果不调用不会阻塞。
    

     

  6. 线程有哪些状态?
    Java中的线程的生命周期大体可分为5种状态。
    (1)新建(NEW):新创建了一个线程对象。
    
    (2)可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。
    该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
    
    (3)运行(RUNNING):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执
    行程序代码。
    
    (4)阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,
    暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)
    状态。阻塞的情况分三种:
    (一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
    (二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线
    程放入锁池(lock pool)中。
    (三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请
    求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完
    毕时,线程重新转入可运行(runnable)状态。
    
    (5)死亡(DEAD):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周
    期。死亡的线程不可再次复生。

     

  7. sleep() 和 wait() 有什么区别?
    (1) wait来自Object类中的方法,sleep是Thead类中的方法。
    
    (2)sleep不会释放对象锁,wait会释放对象锁。
    
    (3)sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,
    实际上还是a去睡觉,要让b线程睡觉要在b的代码中调用sleep。
    
    (4)wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关
    的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤
    醒等待的线程。
    
    (5)使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用。
        synchronized(x){
        x.notify()
        //或者wait()
        }
    
    (6)sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常。

     

  8. notify()和 notifyAll()有什么区别?
    (1)调用了对象的 notifyAll()方法(唤醒所有 wait 线程)。
    
    (2) notify()方法(只随机唤醒一个 wait 线程)。
    
    (3)notify可能会导致死锁,而notifyAll则不会。

     

  9. 线程的 run()和 start()有什么区别?
    (1)run()相当于线程的任务处理逻辑的入口方法,它由Java虚拟机在运行相应线程时直接调
    用,而不是由应用代码进行调用。
    
    (2)start()的作用是启动相应的线程。启动一个线程实际是请求Java虚拟机运行相应的线程,
    而这个线程何时能够运行是由线程调度器决定的。start()调用结束并不表示相应线程已经开始
    运行,这个线程可能稍后运行,也可能永远也不会运行。

     

  10. 创建线程池有哪几种方式?
    Java通过Executors提供四种线程池,分别为:
    (1)newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空
    闲线程,若无可回收,则新建线程。
    
    (2)newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    
    (3)newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
    
    (4)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,
    保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
    
    (5)线程池的一个建议:线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor
     的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。Executors
    利用工厂模式向我们提供了4种线程池实现方式,但是并不推荐使用,原因是使用Executors创建线程池
    不会传入拒绝策略这个参数而使用默认值所以我们常常忽略这一参数,而且默认使用的参数会导致资源
    浪费,不可取。
    
    说明:Executors 各个方法的弊端:
    1)newFixedThreadPool 和 newSingleThreadExecutor:主要问题是堆积的请求处理队列可能会耗费
    非常大的内存,甚至 OOM。
    2)newCachedThreadPool 和 newScheduledThreadPool:主要问题是线程数最大数是 
    Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至 OOM。
    
    

     

  11. 线程池都有哪些状态?
    (1)RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。
    (2)SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。
    (3)STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。
    (4)TIDYING:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执
    行钩子方法 terminated()。
    (5)TERMINATED:terminated()方法结束后,线程池的状态就会变成这个。

     

  12. 线程池中 submit()和 execute()方法有什么区别?
    (1)接收的参数不一样;submit是callable,execute是runnable。
    
    (2)submit()有返回值,而execute()没有;
    例如,有个validation的task,希望该task执行完后告诉我它的执行结果,是成功还是失败,
    然后继续下面的操作。
    
    (3)submit()可以进行Exception处理;
    例如,如果task里会抛出checked或者unchecked exception,而你又希望外面的调用者能够感
    知这些exception并做出及时的处理,那么就需要用到submit,通过对Future.get()进行抛出
    异常的捕获,然后对其进行处理。

     

  13. 在 java 程序中怎么保证多线程的运行安全?
  14. 多线程锁的升级原理是什么?
  15. 什么是死锁?
  16. 怎么防止死锁?
  17. ThreadLocal 是什么?有哪些使用场景?
  18. 说一下 synchronized 底层实现原理?
  19. synchronized 和 volatile 的区别是什么?
  20. synchronized 和 Lock 有什么区别?
  21. synchronized 和 ReentrantLock 区别是什么?
  22. 说一下 atomic 的原理?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值