美文网首页Java多线程
Java多线程面试题大全

Java多线程面试题大全

作者: Android小悟空 | 来源:发表于2018-11-17 11:36 被阅读12次

    以下这些面试题是我对着多线程的知识点自己一点点总结下来的,如果有不全的地方欢迎大家留言一起探讨。

    多线程和并发、并行的区别:

    多线程:是指这个程序运行时产生了不止一个线程

    并行:多个CPU同时处理一段逻辑

    并发:通过cpu调度算法,让用户觉得是在同时进行,但cpu内部并不是真正的同时

    多线程是实现并发机制的一种有效手段

    多线程有哪些状态:

    1、新建:在new Thread时,jvm会像普通对象一样给线程分配内存,并初始化其成员变量的值

    2、就绪:当执行了start方法后,该线程便处于就绪状态,但是它并没有运行,只是表示可以运行了。(注意,当线程被阻塞后重新恢复后,必须先经过就绪状态)

    3、运行:如果就绪状态的线程获得了CPU,那么执行run方法后,该线程会处于运行状态,

    如果计算机只有一个CPU,那么在任何时刻,只有一个线程处于运行状态。在多处理器的机器上,会有多个线程并行执行。当线程数大于CPU数时,依然会有多个线程在同一CPU上轮换(即并发)的现象。

    4、阻塞:可以理解为暂停执行该线程

    5、死亡:run或call执行完成后;抛出未捕获的异常后;直接调用stop方法后,线程处于死亡状态

    有哪些方法可以让线程进入阻塞状态,然后又如何恢复线程到运行状态

    使线程进入阻塞状态的方法:

    1、调用sleep方法主动放弃所占用的处理器资源

    2、调用了一个阻塞式的IO方法:如等待某个输入输出流的完成

    3、线程试图得到一个锁,而该锁正在被其他线程调用

    4、线程在等待某个通知(notify)

    5、调用suspend方法暂停了线程,暂停后的线程必须通过resume方法来恢复,容易造成死锁,一般不用

    恢复线程到运行状态:

    1、sleep方法的线程经过了指定的时间

    2、阻塞式的IO方法已经返回

    3、成功的获取到了试图得到的锁

    4、线程正在等等某个通知时,其他线程发出了一个通知

    5、调用了resume方法

    如何判断线程是否死亡:

    可以调用线程对象的isAlive方法,当处于就绪、运行、阻塞时,返回true。当处于新建或死亡时,返回false

    能不能对一个死亡的线程重新调用start方法让它重新启动:

    不能,死亡就是死亡,该线程将不可再次作为线程执行

    就绪状态的线程如何获取处理器资源:

    线程从就绪状态到运行状态不受程序控制,而是根据系统线程调用所决定,当处于就绪状态的线程获得到处理器资源时,会进入运行状态。而当处于运行状态的线程失去处理器资源时,会处于就绪状态。但是yield方法可以使线程从运行状态转入就绪状态

    Java程序每次运行至少启动几个线程

    两个线程,一个是主线程,一个是垃圾回收机制的线程

    如果没有启动start而是直接启动线程的run方法会怎么样:

    虚拟机会把这个线程当做一个普通的对象,而run方法也会被看做是一个普通的对象中的方法

    Join()在多线程中的作用:

    让一个线程等待另一个线程完成,比如:我创建了一个MyThread线程:

    MyThread myThread = new MyThread();

    然后在main()方法中调用(本质是在main线程中调用)myThread.join()方法,那么main线程会进入阻塞状态直到MyThread线程中的run方法的执行完毕后才会继续执行。

    什么是后台线程:

    有一种线程,是在后台运行的,它的任务是为其他线程提供服务,又称为“守护线程”,

    比如JVM的垃圾回收线程就是一个后台线程。后台线程有一个特征,就是如果所有前台线程全部死亡,那么后台线程会自动死亡。

    线程睡眠Sleep(long millis):

    可以让线程暂停一段时间,当线程进入睡眠状态后,该线程不会获得执行机会,即使系统中没有其他可以执行的线程,处于sleep中的线程也不会执行,直到睡眠结束

    sleep()和wait()的区别:

    最大的区别是,sleep()在睡眠后不会释放掉锁,而wait()在睡眠后会释放掉锁。

    线程让步yield():

    将当前正在执行的线程暂停,但是是将线程进入到就绪状态,释放CPU资源

    线程优先级是什么,如何改变线程优先级:

    每个线程都有一定的优先级,优先级高的线程会获得到更多的执行机会。每个线程的优先级和创建它的父线程的优先级相同,Thread提供了setPriority方法来设定优先级,参数范围为1-10

    什么是线程安全,什么是线程不安全(synchronized的作用或者由来)

    线程的run方法不具有同步安全性,当多个线程同时处理一个共享数据时,可能导致数据混乱,这就是线程不安全。所以引入了synchronized来解决此问题。被synchronized锁定的同步代码块,只能同时被一个线程获取到,当该线程执行完此方法后,会释放掉该锁,这时其他线程才可以继续获取该锁。Synchronized()括号内可以传任何参数,即Obj类型,但通常是被共同访问的共享资源来作为同步监视器

    同步方法是什么,如何使用:

    被synchronized修饰的方法,成为同步方法,如:

    Public synchronized void getPerson(){};

    当内部类中的代码块被synchronized(this)修饰时,请问这个this指的是内部类还是其父类:

    内部类

    当一个线程访问某个类中的被synchronized修饰的方法时,另一个线程可以访问该类中其他没有被synchronized修饰的方法吗:

    可以

    当一个线程访问某个类中的被synchronized修饰的方法时,另一个线程可以访问该类中其他被synchronized修饰的方法吗:

    不可以,因为Java中的每个对象都有一个锁(lock),或者叫做监视器(monitor),当一个线程访问某个对象的synchronized方法时,将该对象上锁,其他任何线程都无法再去访问该对象的synchronized方法了(这里是指所有的同步方法,而不仅仅是同一个方法),直到之前的那个线程执行方法完毕后(或者是抛出了异常),才将该对象的锁释放掉,其他线程才有可能再去访问该对象的synchronized方法。

    Synchronized如何被释放:

    1、当前线程的同步方法,同步代码块执行结束

    2、出现了未处理的Error或Exception,导致代码块结束

    3、当线程正在执行加锁的代码块或同步方法时,调用了wait()方法,那么会使线程进入阻塞状态,并且释放锁

    4、注意:当线程正在执行加锁的代码块或同步方法时,调用sleep()方法或者yield()方法,不会释放锁

    什么是死锁,什么情况下会出现死锁:

    当所有线程处于阻塞状态,整个程序没有发生异常,也不会有任何提示,就进入了死锁状态;

    当两个线程相互等待对方释放锁时,就会发生死锁。

    什么是Lock锁,和synchronized有什么区别:

    1、Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;

    2、synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

    3、Lock可以通过tryLock()方法知道是否成功获取到锁,但是synchronized不行

    4、Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

    5、Lock可以提高多个线程进行读操作的效率(读写锁)。

    6、Lock可以实现公平锁,Synchronized不保证公平性。

    线程间通信:

    wait()/notify()机制:

    ThreadA处于阻塞状态(wait方法),ThreadB在run方法中对某个数据做操作,当数据达到我设定的某个条件时,通过notify()来唤醒ThreadA。

    好处:提高了CPU的利用率

    缺点:如果通知过早,会打乱执行的逻

    其他通信方法请参考:

    http://www.importnew.com/26850.html

    线程池:

    为了避免重复创建线程,线程池可以的出现可以让线程进行复用,当需要时,从线程池中取出一个线程,当工作完成后,并不是直接关闭线程,而是将线程归还给线程池供其他任务使用。

    常用的线程池:

    newFixedThreadPool

    固定大小的线程池,可以指定线程池的大小,该线程池corePoolSize和maximumPoolSize相等,阻塞队列使用的是LinkedBlockingQueue,大小为整数最大值。

    newSingleThreadExecutor

    单个线程线程池,只有一个线程的线程池,阻塞队列使用的是LinkedBlockingQueue,若有多余的任务提交到线程池中,则会被暂存到阻塞队列,待空闲时再去执行。按照先入先出的顺序执行任务。

    newCachedThreadPool

    缓存线程池,缓存的线程默认存活60秒。线程的核心池corePoolSize大小为0,核心池最大为Integer.MAX_VALUE,阻塞队列使用的是SynchronousQueue。是一个直接提交的阻塞队列,他总会迫使线程池增加新的线程去执行新的任务。在没有任务执行时,当线程的空闲时间超过keepAliveTime(60秒),则工作线程将会终止被回收,当提交新任务时,如果没有空闲线程,则创建新线程执行任务,会导致一定的系统开销。如果同时又大量任务被提交,而且任务执行的时间不是特别快,那么线程池便会新增出等量的线程池处理任务,这很可能会很快耗尽系统的资源。

    newScheduledThreadPool

    定时线程池,该线程池可用于周期性地去执行任务,通常用于周期性的同步数据。

    相关文章

      网友评论

        本文标题:Java多线程面试题大全

        本文链接:https://www.haomeiwen.com/subject/ltmbfqtx.html