美文网首页
线程面试题

线程面试题

作者: 行者和他的钢笔 | 来源:发表于2018-09-18 08:40 被阅读6次

    1、Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,他们有什么区别?

    (1)sleep 是线程类(Thread)的方法,wait 是Object 类的方法。
    (2)最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
    (3)wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)
    (4)sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常。

    2、线程的sleep()方法和yield()方法有什么区别?

    sleep()方法和yield()方法都是Thread类的静态方法,都会使当前处于运行状态的线程放弃CPU,把运行机会让给别的线程。两者的区别在于:
    (1)【运行机会,考虑不考虑其他线程的优先级】sleep()方法会给其他线程运行的机会,不考虑其他线程的优先级,因此会给较低优先级线程一个运行的机会;yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。
    (2)【执行相应方法后的状态】当线程执行了sleep(long millis)方法,将转到阻塞状态,参数millis指定睡眠时间;当线程执行了yield()方法,将转到就绪状态。
    (3)【是否抛异常】sleep()方法声明抛出InterruptedException异常,而yield()方法没有声明抛出任何异常。
    (4)sleep()方法比yield()方法具有更好的可移植性。

    3、请说出与线程同步以及线程调度相关的方法

    -wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;

    -sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常;

    -notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且与优先级无关;

    -notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;

    4、编写多线程程序有几种实现方式

    (1)继承Thread类,重写 Thread 类的 run 方法。然后就是分配并启动该子类的实例
    (2)实现Runnable 接口,该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。
    (3)Java 5以后创建线程还有第三种方式:通过线程池,实现Callable接口,该接口中的call方法可以在线程执行结束时产生一个返回值
    Java 5

    6、线程池

    什么是线程池?【可以将线程池的作用一块回答】

    线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用。
    (1)减少了创建和销毁线程的次数,节省创建和销毁线程的时间和系统资源的开销。
    (2)可以根据系统的承受能力,调整线程池中线程的数目,防止出现资源不足或内存消耗太多的情况。

    创建线程池

    通常,线程池都是通过线程池工厂创建,再调用线程池中的方法获取线程,再通过线程去执行任务方法。

    Java四种线程池的使用:

    Java通过Executors提供四种线程池,分别为:
    newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

    newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

    newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

    newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

    使用线程池方式:
    (1)使用线程池方式--Runnable接口
    (2)使用线程池方式—Callable接口
    Callable接口:与Runnable接口功能相似,用来指定线程的任务。其中的call()方法,用来返回线程任务执行完毕后的结果,call方法可抛出异常。

    7、线程的基本状态以及状态之间的关系?

    图片.png

    【new:新建状态;wating:等待状态;runnable:就绪状态;running:运行状态;blocked:阻塞状态;dead:死亡状态】
    1.新建
    用new语句创建的线程对象处于新建状态,此时它和其他java对象一样,仅被分配了内存。

    2.等待
    当线程在new之后,并且在调用start方法前,线程处于等待状态。

    3.就绪
    当一个线程对象创建后,其他线程调用它的start()方法,该线程就进入就绪状态。处于这个状态的线程位于Java虚拟机的可运行池中,等待cpu的使用权。

    4.运行状态

    处于这个状态的线程占用CPU,执行程序代码。在并发运行环境中,如果计算机只有一个CPU,那么任何时刻只会有一个线程处于这个状态。
    只有处于就绪状态的线程才有机会转到运行状态。

    5.阻塞状态

    阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行。当线程处于阻塞状态时,Java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,它才会有机会获得运行状态。

    阻塞状态分为三种:

    1、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。

    2、同步阻塞:运行的线程在获取对象同步锁时,若该同步锁被别的线程占用,则JVM会把线程放入锁池中。

    3、其他阻塞:运行的线程执行Sleep()方法,或者发出I/O请求时,JVM会把线程设为阻塞状态。当Sleep()状态超时、或者I/O处理完毕时,线程重新转入就绪状态。

    6.死亡状态

    当线程执行完run()方法中的代码,或者遇到了未捕获的异常,就会退出run()方法,此时就进入死亡状态,该线程结束生命周期。

    5、synchronized关键字的用法

    线程同步的方式有两种:

    方式1:同步代码块

    同步代码块: 在代码块声明上 加上synchronized
    synchronized (锁对象) {
    可能会产生线程安全问题的代码
    }
    同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。


    同步代码块执行原理

    加了同步之后,线程进同步需要判断锁,获取锁,出同步需要释放锁,导致程序运行速度的下降

    方式2:同步方法

    好处:代码简洁

    将共享数据和同步抽取到一个方法中

    8、Lock接口

    Lock提供了一个更加面对对象的锁,在该锁中提供了更多的操作锁的功能。我们使用Lock接口,以及其中的lock()方法和unlock()方法替代同步。

    8、synchronized和java.util.concurrent.locks的区别

    (1)synchronized和Lock接口都可以实现同步访问。
    (2)synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;
    (3)在同步锁的释放上:
    如果一个代码块或者一个方法被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:
      1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;
      2)线程执行发生异常,此时JVM会让线程自动释放锁。

    如果采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。

    知识点总结

    相关文章

      网友评论

          本文标题:线程面试题

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