java并发面试题(一)基础

本文整理了常见的Java并发面试题,希望对大家面试有所帮助,欢迎大家互相交流。

多线程

  1. java中有几种方法可以实现一个线程?
  2. 如何停止一个正在运行的线程?
  3. notify()和notifyAll()有什么区别?
  4. sleep()和 wait()有什么区别?
  5. 什么是Daemon线程?它有什么意义?
  6. java如何实现多线程之间的通讯和协作?

  1. 什么是可重入锁(ReentrantLock)?
  2. 当一个线程进入某个对象的一个synchronized的实例方法后,其它线程是否可进入此对象的其它方法?
  3. synchronized和java.util.concurrent.locks.Lock的异同?
  4. 乐观锁和悲观锁的理解及如何实现,有哪些实现方式?

并发框架

  1. SynchronizedMap和ConcurrentHashMap有什么区别?
  2. CopyOnWriteArrayList可以用于什么应用场景?

线程安全

  1. 什么叫线程安全?servlet是线程安全吗?
  2. 同步有几种实现方法?
  3. volatile有什么用?能否用一句话说明下volatile的应用场景?
  4. 请说明下java的内存模型及其工作流程。
  5. 为什么代码会重排序?

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: java并发面试题(一)基础

  • Trackback 关闭
  • 评论 (27)
    • 杰iter
    • 2013/03/10 5:14下午

    答案呢。。。。

    • 小Q
    • 2013/03/12 7:15下午

    最好能附上答案

    • nicky
    • 2013/03/17 5:32下午

    1 应该是可以继承Thread类, 或者实现Runnable接口吧
    2 STOP方法?
    3 notify和notifyall 这个还真的不怎么清楚,notify是唤醒一个线程,notifyall是唤醒所有的等待线程?
    4 只用过SLEEP方法,wait在个人感觉应该是会把该线程从执行队列移出队列到等待队列中吧
    5 , 6 都不知道哎

      • 宅男小何
      • 2013/03/18 9:55上午

      如何停止一个线程?
      最好的办法是设置一个变量,在外面改变这个变量,然后线程每次运行的时候检查这个变量的值。
      如果直接用stop方法容易引起死锁的问题,

      • 这里需要做些纠正,我不知道为什么很多人说stop会导致死锁,但这个说法实在是有问题。stop方法被弃用,并不是因为会导致死锁的缘故,事实上,调用stop后,被stop的线程会抛出一个ThreadDeath错误,如果这个时候线程持有锁的话,它会像遇到一般异常一样处理,并不会有死锁的问题发生。它被弃用的主要原因在于会导致对象状态不一致。而suspend和resume确实会导致死锁。

      • 被弃用的主要原因在于会导致对象状态不一致,您说的这个对象指的是“锁”是吗?

      • wh
      • 2018/08/04 10:34上午

      1.通过设置停止标志实现线程退出
      2.通过报异常的方式实现

    • tsingxu
    • 2013/03/20 5:24下午

    1 通过创建Thread
    2 条件变量
    3 随机唤醒和唤醒全部
    4 定时等待和在监视器上等待,不同范畴
    5 守护线程,不需要上层逻辑介入的后台线程 ,比如GC
    6 中断和 直接或间接访问对方实例

    1 更高级的锁,附加更多特性
    2 可进入非synchronized方法
    3 后者具有更丰富的特性
    4 乐观锁是假设我已经拿到锁,悲观所是我必须拿到锁,前者用CAS,后者用mutex

    1 后者具有更高的并发
    2 多读少写

    1 在多线程调用情况下,依然表现正常
    2 锁和volatile
    3 保持可见性,在1写N读的情况下比较适合
    4 太多了,我只知道一些
    5 编译器旨在提升性能

    • 答得不错,ReentrantLock和JMM可以再补充下。

        • tsingxu
        • 2013/03/21 11:07上午

        1 ReentrantLock 相对于固有锁synchronized,同样是可重入的,在某些vm版本上提供了比固有锁更高的性能,提供了更丰富的锁特性,比如可中断的锁,可等待的锁,平等锁以及非块结构的加锁。从代码上尽量用固有锁,vm会对固有锁做一定的优化,并且代码可维护和稳定。只有在需要ReentrantLock的一些特性时,可以考虑用ReentrantLock实现。

        2 JVM的内存模型可简单理解为,有一块整个JVM共享的主内存,每个线程有自己的变量复本,线程持有的复本与主内存之间使用内部的数据协议,再具体可参考一些blog和周志明的深入理解JVM12章

    • 张蒙蒙
    • 2013/03/27 9:45上午

    ReentrantLock 和synchronized比较:
    性能上:
    synchronized在Java5.0性能大胜synchronized,Java 6中synchronized 略有胜出—-摘自《java并发编程实战》(13.4)
    当时我说synchronized在今后的JVM(JIT)优化的可能性比ReentrantLock大,回来后我翻翻资料,发现在ReentrantLock 和synchronized还真有一些需要了解的知识,所以特别整理下发给大家。
    1.为什么JUC框架出现LOCK?
    ReentrantLock并不是替代synchronized的方法,而是当内置锁不适用时,作为一种可选的高级功能。
    2.那么Synchronized有哪些缺点?
    ①. 只有一个condition与锁相关联,这个condition是什么?就是synchronized对针对的对象锁。
    ②. synchronized无法中断一个正在等待获得锁的线程,也即多线程竞争一个锁时,其余未得到锁的线程只能不停的尝试获得锁,而不能中断。这种情况对于大量的竞争线程会造成性能的下降等后果。
    可见ReentrantLock 是对synchronized补充。
    3.我们面对ReentrantLock和synchronized改如何选择?
    Synchronized相比Lock,为许多开发人员所熟悉,并且简洁紧凑,如果现有程序已经使用了内置锁,那么尽量保持代码风格统一,尽量不引入Lock,避免两种机制混用,容易令人困惑,也容易发生错误。
    在Synchronized无法满足需求的情况下,Lock可以作为一种高级工具,这些功能包括“可定时的、可轮询的与可中断的锁获取操作,公平队列,以及非块结构的锁”否则还是优先使用Synchronized。
    最后,未来更可能提升Synchronized而不是Lock的性能,因为Synchronized是JVM的内置属性,他能执行一些优化,例如对线程封闭的锁对象的锁消除优化,通过增加锁的粒度来消除内置锁的同步,而如果基于类库的锁来实现这些功能,则可能性不大。—以上建议摘自《java并发编程实战》(13.4)

    • wkiskey
    • 2013/08/20 6:14下午

    果然是个好网站

    • wkiskey
    • 2013/08/20 6:16下午

    果然是学习必备啊

    • 匿名
    • 2013/12/02 1:14下午

    1.

    • 匿名
    • 2013/12/29 12:17下午

    多线程

    1. java中有几种方法可以实现一个线程?
    可以使用Runnable,Callable,Thread或者线程池
    2. 如何停止一个正在运行的线程?
    可以使用正在运行的线程,支持线程中断,那么可以使用线程中断的方法停止这个线程;通常是定义一个volatile的状态变量,在运行线程线程中读这个变量,其它线程中修改这个变量
    3. notify()和notifyAll()有什么区别?
    notify是随机唤醒一个等待某个资源的线程,进入就绪队列等待CPU的调度,notifyAll是唤醒所有的,进入就绪队列等待CPU调度
    4.sleep()和 wait()有什么区别?
    sleep()是当前正在运行的线程主动放弃CPU,进入睡眠状态,如果此时线程已经持有一个锁,则释放这个锁
    wait()是等待其它其它线程对某个共享资源的锁释放,等待期间,仍然持有它已经获得的同步锁,这个就是典型的两个线程互相等待对方持有的资源以致死锁的原因
    5.什么是Daemon线程?它有什么意义?
    守护线程是后台线程,它通常属于低优先级的线程,守护用户线程,通常做一些垃圾清理的工作,比如GC。当所有的用户线程退出后,守护线程不会立即退出,还出执行一段时间,具体多少时间,有知道的告诉我。。。
    6.java如何实现多线程之间的通讯和协作?
    同步和互斥,资源互斥、协调竞争是要解决的因,同步是竞争协调的果。可以使用synchnized/notify/notifyAll以及Lock/Condition, CyclicBarrier/Semaphore/Countdownbatch。线程的join以及Future/FutureTask是为了解决多线程计算后的结果统计

      • 匿名
      • 2014/03/18 2:16下午

      第四点回答有误,sleep的时候锁并没有被释放;而wait将当前线程挂起,并释放锁。

        • 丰富
        • 2014/04/15 6:02下午

        没错,sleep方法是在指定的时间内让正在执行的线程暂停执行,但不会释放锁。而wait方法是让当前线程等待,直到其他线程调用对象的notify或notifyAll方法。wait方法会释放掉锁,使别的线程有机会占用锁。

    • 匿名
    • 2013/12/29 12:25下午

    1. 什么是可重入锁(ReentrantLock)?
    2. 当一个线程进入某个对象的一个synchronized的实例方法后,其它线程是否可进入此对象的其它方法?
    能否进入关键是看其它方法是否是同步于此对象
    3. synchronized和java.util.concurrent.locks.Lock的异同?

    4. 乐观锁和悲观锁的理解及如何实现,有哪些实现方式?
    乐观锁,每次操作时不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止
    悲观锁是会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。
    乐观锁可以使用volatile+CAS原语实现
    悲观锁可以使用synchronize的以及Lock。

    • 匿名
    • 2013/12/29 12:33下午

    纠正下。。。

    sleep()是当前正在运行的线程主动放弃CPU,进入睡眠状态,如果此时线程已经持有一个锁,则释放这个锁。。。。应该是说,sleep的线程不会释放它已获得的锁。

  1. 囧,竟然有3道题目不会。。。不开心啊,继续努力了

  2. 竟然有3道题目不会。。囧,不开心啊。。

    • 程序员小董
    • 2016/04/15 10:31上午

    并发编程网的内容都很好
    但是我有一个小建议
    版面布局能不能修改一下
    整个屏幕有一小半是被右边的推荐文章和左边的文章信息占用了
    这个能不能优化一下?

    • 这个是模板这么设计的,我想办法优化下吧

        • wh
        • 2018/08/04 10:38上午

        发现一个有趣的问题,工作日打开网站会异常缓慢,但是周末就是秒开!

    • lunardancer
    • 2017/08/22 9:42下午

    在代码执行过程中,有3层对原子性的处理。第1层是lock或者synchronized,分别使用state和monitor的count去维护重入次数,使用unsafe包的cas来维护原子性,都是使用阻塞队列完成对阻塞任务的等待;第2层是unsafe包内的cas的原子性实现,使用自旋的方式,来确保改变的数值的并发行;第3层是具体cpu内核层保证原子性的实现,在jvm运行时编译过程,会在原子操作前加#LOCK汇编操作,对于#LOCK的具体cpu实现,会使用锁总线或是cpu缓存一致性原则mesi来实现,前者对资源损耗较大,后者不需要锁总线,依赖cpu间通信完成缓存一致性操作。
    基于上述3层对原子性的实现,保证了代码的逻辑结构的原子性操作需求.

    • cczz
    • 2019/05/28 11:57上午

    1。继承Thead 和 实现Runnable, 其实Runnable也是用Thead对象这run里调用 Runnable的方法

    2.使用Thead的中断和设置共享变量,两者都需被停止的线程自己主动检查。

    3.唤醒堵塞在这个锁上的随机一个和唤醒全部

    4。sleep不会放开锁 ,wait会放开。调用wait必须先获取锁,也就是要写在synchronized里面

    5.守护线程,进程不退出它就不退出,列如gc

    6。共享变量和锁

    1 已经持有这把锁的对象可以再次加锁,内部会维护一个共享变量,加锁+1 解锁-1,为0时才能被别人抢占。 所以使用重复加锁也要重复解锁

    2 不可进入synchroized修饰的方法

    3 都是可重入锁,java后面优化后性能和功能差距不大,lock可以实现公平锁

    4

    1 前者只是在方法上加入synchronized 锁的粒度很大 ,后者是在map的”桶“上加锁,如果两个线程操作不是一个”桶“则可以同时进行 。性能更好

    2 在写时复制。修改时不影响读,读多写少的情况

    1 线程安全:就是所有情况都在”掌控”之中,所有情况都是可以预料和可以接受的 。servlet不是线程安全,但是spring的编程模式让我们尽量远离线程安全问题。

    2 synchronized , 锁 ,使用共享变量做标示线程自旋等待

    3 内存屏障,防止指令重排,保证可见性,一个线程的修改一定会被其他线程看见

    遵循happens-before 场景 :修饰共享变量

    4 太多了

    5 优化性能,操作是在栈上进行,可以连续操作同一个变量,减少弹入弹出操作

    对cpu 的缓存行也友好

return top