java面试题---多线程

  1. 并行和并发有什么区别?
    并发:指在同一时刻做不止一件事情。
    并行:指将大量的任务,拆解成多个子任务分配到多个线程上,并发的执行。

  2. 线程和进程的区别?
    进程是资源分配的最小单位,线程是程序执行的最小单位
    进程有自己的独立地址空间,而线程是共享进程中的数据的,使用相同的地址空间。
    多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响。

  3. 守护线程是什么?
    守护线程(即daemon thread),是个服务线程,准确地来说就是服务其他的线程,这是它的作用——而其他的线程只有一种,那就是用户线程。所以java里线程分2种:
    1、守护线程,比如垃圾回收线程,就是最典型的守护线程。
    2、用户线程,就是应用程序里的自定义线程。

  4. 创建线程有哪几种方式?
    继承Thread类创建线程类
    通过Runnable接口创建线程类
    通过Callable和FutureTask创建线程
    通过线程池创建线程

  5. 说一下 runnable 和 callable 有什么区别?
    实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;
    Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;

  6. 线程有哪些状态?
    新建状态、就绪状态、运行状态、阻塞状态、死亡状态

  7. sleep() 和 wait() 有什么区别?
    sleep()是线程线程类(Thread)的方法
    wait()是Object的方法
    sleep方法只让出了CPU,而并不会释放同步资源锁
    wait()方法则是指当前线程释放同步资源锁,只有调用了notify()方法才能唤醒。

  8. notify()和 notifyAll()有什么区别?
    notify():唤醒一个处于等待状态的线程
    notifyAll():唤醒所有处入等待状态的线程;

  9. 线程的 run()和 start()有什么区别?
    start()方法来启动线程。这时此线程是处于就绪状态, 并没有运行。 然后通过此Thread类调用方法run()来完成其运行操作的。
    run()方法当作普通方法的方式调用。

  10. 创建线程池有哪几种方式?
    newSingleThreadExecutor、newFixedThreadPool、newCachedThreadPool、newScheduledThreadPool

  11. 线程池都有哪些状态?
    线程池的5种状态:Running、ShutDown、Stop、Tidying、Terminated

  12. 线程池中 submit()和 execute()方法有什么区别?
    submit()方法,可以提供Future 类型的返回值,不会抛出异常,入参可以为Callable。
    executor()方法,无返回值,会抛出异常,入参Runnable。

  13. 在 java 程序中怎么保证多线程的运行安全?
    保证三要素:
    原子性(Synchronized, Lock)
    有序性(Volatile,Synchronized, Lock)
    可见性(Volatile,Synchronized,Lock)

  14. 多线程锁的升级原理是什么?
    线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,则自旋获取锁,当自旋获取锁仍然失败时,表示存在其他线程竞争锁(两条或两条以上的线程竞争同一个锁),则轻量级锁会膨胀成重量级锁

  15. 什么是死锁?
    线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。

  16. 怎么防止死锁?
    互斥条件、请求与保持条件、不可剥夺条件、循环等待条件 破坏其中一个条件即可

  17. ThreadLocal 是什么?有哪些使用场景?
    ThreadLocal是用来维护本线程的变量的,并不能解决共享变量的并发问题。ThreadLocal是各线程将值存入该线程的map中,以ThreadLocal自身作为key,需要用时获得的是该线程之前存入的值。如果存入的是共享变量,那取出的也是共享变量,并发问题还是存在的。
    ThreadLocal的主要用途是为了保持线程自身对象和避免参数传递,主要适用场景是按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。

  18. 说一下 synchronized 底层实现原理?
    synrhronized关键字简洁、清晰、语义明确,因此即使有了Lock接口,使用的还是非常广泛。其应用层的语义是可以把任何一个非null 对象 作为"锁",当synchronized作用在方法上时,锁住的便是对象实例(this);当作用在静态方法时锁住的便是对象对应的Class实例,因为 Class数据存在于永久带,因此静态方法锁相当于该类的一个全局锁;当synchronized作用于某一个对象实例时,锁住的便是对应的代码块。

  19. synchronized 和 volatile 的区别是什么?
    volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
    volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
    volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
    volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
    volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

  20. synchronized 和 Lock 有什么区别?
    1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
    2.synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
    3.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
    4.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
    5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)
    6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

  21. synchronized 和 ReentrantLock 区别是什么?
    1 Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
    2 synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
    3 Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
    4 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
    5 Lock可以提高多个线程进行读操作的效率。

  22. 说一下 atomic 的原理?
    Atomic包是java.util.concurrent下的另一个专门为线程安全设计的Java包,包含多个原子操作类。这个包里面提供了一组原子变量类。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入,这只是一种逻辑上的理解。实际上是借助硬件的相关指令来实现的,不会阻塞线程(或者说只是在硬件级别上阻塞了)。可以对基本数据、数组中的基本数据、对类中的基本数据进行操作。原子变量类相当于一种泛化的volatile变量,能够支持原子的和有条件的读-改-写操作。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java面试题真的很多,下面我来回答一个有关多线程的问题。 在Java中实现多线程有两种方式,一种是继承Thread类,另一种是实现Runnable接口。这两种方式有何区别? 继承Thread类的方式是直接定义一个类继承Thread,并重写它的run()方法。然后创建该类的对象,并调用对象的start()方法来启动线程。这种方式简单直接,但因为Java是单继承的,所以如果某个类已经继承了其他类,就不能再直接继承Thread类实现多线程。 实现Runnable接口的方式是定义一个类实现Runnable接口,并实现其唯一的抽象方法run()。然后创建Thread类的对象,将实现了Runnable的对象作为参数传递给Thread类的构造方法。最后调用Thread对象的start()方法来启动线程。这种方式灵活性更大,因为Java允许一个类实现多个接口,所以即使某个类已经继承了其他类,仍然可以通过实现Runnable接口来实现多线程。 另一个区别在于资源共享的问题。继承Thread类的方式,不管是数据还是方法,都是线程自己拥有的,不存在共享的情况。而实现Runnable接口的方式,多个线程可以共享同一个对象的数据和方法,因为多个线程共同操作的是同一个Runnable对象。 总结来说,继承Thread类方式简单直接,但只能通过单继承来实现多线程;实现Runnable接口方式更灵活,可以解决单继承的限制,并且多个线程可以共享同一个Runnable对象的数据和方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值