面试题-Java多线程

27 篇文章 0 订阅
6 篇文章 0 订阅

一、其他多线程问题

  1. 为何要使用同步? 关于线程同步(7种方式):http://www.php.cn/java-article-407607.html
  2. 线程的五种状态:https://www.cnblogs.com/jijijiefang/articles/7222955.html
  3. sleep和wait的区别:https://www.cnblogs.com/muhe221/articles/4345708.html
  4. notify和notifyAll的区别:http://www.importnew.com/21501.html
  5. CAS(Compare and Swap,java.util.concurrent包中借助CAS实现了区别于synchronouse同步锁的一种乐观锁)原理深度分析:https://blog.csdn.net/hsuxu/article/details/9467651
  6. 说说线程安全问题:http://www.jasongj.com/java/thread_safe/
  7. synchronize 实现原理:http://cmsblogs.com/?p=2071
  8. volatile和synchronized区别:https://www.cnblogs.com/tf-Y/p/5266710.htmlsynchronized底层实现:1)进入时,执行 monitorenter,将计数器 +1,释放锁 monitorexit 时,计数器-1。2)当一个线程判断到计数器为 0 时,则当前锁空闲,可以占用;反之,当前线程进入等待状态。monitor 机制:Synchronized 是在加锁,加对象锁。对象锁是一种重量锁(monitor),synchronized 的锁机制会根据线程竞争情况在运行时会有偏向锁(单一线程)、轻量锁(多个线程访问 synchronized 区域)、对象锁(重量锁,多个线程存在竞争的情况)、自旋锁等。
  9. volatile 实现原理:http://www.cnblogs.com/paddix/p/5428507.html
  10. volatile怎么实现可见性的:1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。2.当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。volatile的作用:1)主内存和工作内存,直接与主内存产生交互,进行读写操作,保证可见性;2)禁止 JVM 进行的指令重排序。

  11. 请描述ThreadLocal原来及用途:http://blog.51cto.com/lavasoft/51926
  12. ThreadLocal 内部实现机制:1)每个线程内部都会维护一个类似 HashMap 的对象,称为 ThreadLocalMap,里边会包含若干了 Entry(K-V 键值对),相应的线程被称为这些 Entry 的属主线程;2)Entry 的 Key 是一个 ThreadLocal 实例,Value 是一个线程特有对象。Entry 的作用即是:为其属主线程建立起一个 ThreadLocal 实例与一个线程特有对象之间的对应关系。3)Entry 对 Key 的引用是弱引用;Entry 对 Value 的引用是强引用。

  13. Lock接口有哪些实现类,使用场景是什么、可重入锁的用处及实现原理,写时复制的过程,读写锁,分段锁(ConcurrentHashMap中的segment):https://blog.csdn.net/fly910905/article/details/79765381
  14. Lock与synchronized 的区别:https://www.cnblogs.com/iyyy/p/7993788.html
  15. ReentrantLock与synchronized的区别:http://cmsblogs.com/?p=2210
  16. AQS(AbstractQueuedSynchronizer):https://blog.csdn.net/zcw4237256/article/details/78552741
  17. 悲观锁和乐观锁区别:https://blog.csdn.net/rexct392358928/article/details/52230737
  18. CAS 乐观锁及ABA问题:http://www.importnew.com/20472.html
  19. ABC三个线程如何保证顺序执行:https://blog.csdn.net/difffate/article/details/63684290
  20. 产生死锁4个必要条件:1)互斥条件:一个资源每次只能被一个线程使用;2)请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放;3)不剥夺条件:进程已经获得的资源,在未使用完之前,不能强行剥夺;4)循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。
  21. 如何避免死锁:https://blog.csdn.net/qq_38663729/article/details/80058980
  22. Atomic关键字:可以使基本数据类型以原子的方式实现自增自减等操作。适合在高并发的情况下使用。concurrent.atomic包下包括:AtomicInteger、AtomicBoolean、AtomicLong等:https://blog.csdn.net/u013803262/article/details/72452932
  23. AtomicInteger:https://www.cnblogs.com/scuwangjun/p/9098057.html
  24. java常用的几种线程池比较:https://www.cnblogs.com/aaron911/p/6213808.html
  25. 线程池:java.util.concurrent.ThreadPoolExecutor 类就是一个线程池。客户端调用 ThreadPoolExecutor.submit(Runnable task) 提交任务,线程池内部维护的工作者线程的数量就是该线程池的线程池大小,有 3 种形态:1)当前线程池大小 :表示线程池中实际工作者线程的数量;2)最大线程池大小 (maxinumPoolSize):表示线程池中允许存在的工作者线程的数量上限;3)核心线程大小 (corePoolSize ):表示一个不大于最大线程池大小的工作者线程数量上限。                                        如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队;如果运行的线程等于或者多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不是添加新线程;如果无法将请求加入队列,即队列已经满了,则创建新的线程,除非创建此线程超出 maxinumPoolSize, 在这种情况下,任务将被拒绝。

  26. newFixedThreadPool此种线程池如果线程数达到最大值后会怎么办,底层原理:如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。

  27. 例如同一个类不同方法都有synchronized锁,一个对象是否可以同时访问:不可以,因synchronized方法使用的锁是对象本身,一旦一个方法获得了锁,另外一个方法想要获取这个锁,就要等待锁被释放,所以同一对象的两个synchronized方法不能被同时访问

  28. Java语言中synchronized 修饰在 static方法和 非static方法的区别:https://blog.csdn.net/cs408/article/details/48930803
  29. Java线程池的实现原理:https://www.jianshu.com/p/87bff5cc8d8c
  30. java在处理线程同步时,常用方法有:1)synchronized关键字。2)Lock显示加锁。3)信号量Semaphore。4)CAS算法5)concurrent包。
  31. 进程间的通信:1)管道(Pipe)及有名管道(named pipe)2)信号(Signal)3)消息队列(Message)4)共享内存5)信号量(semaphore)6)套接口(Socket)
  32. 1
  33. 3
  34. 23

二、多线程专题(死磕多线程)

  1. 【死磕Java并发】—–深入分析synchronized 的实现原理synchronized 可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性。深入分析 synchronized 的内在实现机制,锁优化、锁升级过程。
  2. 【死磕Java并发】—–深入分析volatile的实现原理volatile 可以保证线程可见性且提供了一定的有序性,但是无法保证原子性。在 JVM 底层 volatile 是采用“内存屏障”来实现的。这篇博文将带你分析 volatile 的本质
  3. 【死磕Java并发】—–Java内存模型之happens-beforehappens-before 原则是判断数据是否存在竞争、线程是否安全的主要依据,保证了多线程环境下的可见性。定义如下:1)如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。2)两个操作之间存在happens-before关系,并不意味着一定要按照happens-before原则制定的顺序来执行。如果重排序之后的执行结果与按照happens-before关系来执行的结果一致,那么这种重排序并不非法。
  4. 【死磕Java并发】—–Java内存模型之重排序在执行程序时,为了提供性能,处理器和编译器常常会对指令进行重排序,但是不能随意重排序,不是你想怎么排序就怎么排序,它需要满足以下两个条件:1)在单线程环境下不能改变程序运行的结果;2)存在数据依赖关系的不允许重排序。as-if-serial 语义保证在单线程环境下重排序后的执行结果不会改变。
  5. 【死磕Java并发】—–Java内存模型之分析volatilevolatile的内存语义是:1)当写一个 volatile 变量时,JMM 会把该线程对应的本地内存中的共享变量值立即刷新到主内存中。2)当读一个 volatile 变量时,JMM 会把该线程对应的本地内存设置为无效,直接从主内存中读取共享变量。总是说 volatile 保证可见性,happens-before 是 JMM 实现可见性的基础理论,两者会碰撞怎样的火花?这篇博文给你答案。
  6. 【死磕Java并发】—–Java内存模型之从JMM角度分析DCL DCL,即Double Check Lock,双重检查锁定。是实现单例模式比较好的方式,这篇博客告诉你 DCL 中为何要加 volatile 这个关键字。
  7. 【死磕Java并发】—–J.U.C之AQS:AQS简介 AQS,AbstractQueuedSynchronizer,即队列同步器。它是构建锁或者其他同步组件的基础框架(如ReentrantLock、ReentrantReadWriteLock、Semaphore等),为 JUC 并发包中的核心基础组件。
  8. 【死磕Java并发】—–J.U.C之AQS:CLH同步队列 前线程已经等待状态等信息构造成一个节点(Node)并将其加入到CLH同步队列,同时会阻塞当前线程,当同步状态释放时,会把首节点唤醒(公平锁),使其再次尝试获取同步状态。
  9. 【死磕Java并发】—–J.U.C之AQS:同步状态的获取与释放 AQS的设计模式采用的模板方法模式,子类通过继承的方式,实现它的抽象方法来管理同步状态,对于子类而言它并没有太多的活要做,AQS提供了大量的模板方法来实现同步,主要是分为三类:独占式获取和释放同步状态、共享式获取和释放同步状态、查询同步队列中的等待线程情况。
  10. 【死磕Java并发】—–J.U.C之AQS:阻塞和唤醒线程 当需要阻塞或者唤醒一个线程的时候,AQS 都是使用 LockSupport 这个工具类来完成。LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。
  11. 【死磕Java并发】—–J.U.C之重入锁:ReentrantLock 一个可重入的互斥锁定 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁定相同的一些基本行为和语义,但功能更强大。ReentrantLock 将由最近成功获得锁定,并且还没有释放该锁定的线程所拥有。当锁定没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁定并返回。如果当前线程已经拥有该锁定,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。这篇博客带你理解 重入锁:ReentrantLock 内在本质。
  12. 【死磕Java并发】—–J.U.C之读写锁:ReentrantReadWriteLock读写锁维护着一对锁,一个读锁和一个写锁。通过分离读锁和写锁,使得并发性比一般的排他锁有了较大的提升:在同一时间可以允许多个读线程同时访问,但是在写线程访问时,所有读线程和写线程都会被阻塞。读写锁的主要特性:1)公平性:支持公平性和非公平性。2)重入性:支持重入。读写锁最多支持65535个递归写入锁和65535个递归读取锁。3)锁降级:遵循获取写锁、获取读锁在释放写锁的次序,写锁能够降级成为读锁
  13. 【死磕Java并发】—–J.U.C之Condition在没有Lock之前,我们使用synchronized来控制同步,配合Object的wait()、notify()系列方法可以实现等待/通知模式。在Java SE5后,Java提供了Lock接口,相对于Synchronized而言,Lock提供了条件Condition,对线程的等待、唤醒操作更加详细和灵活
  14. 【死磕Java并发】—-深入分析CAS CAS,Compare And Swap,即比较并交换。Doug lea大神在同步组件中大量使用 CAS 技术鬼斧神工地实现了Java 多线程的并发操作。整个 AQS 同步组件、Atomic 原子类操作等等都是以 CAS 实现的。可以说CAS是整个JUC的基石。
  15. 【死磕Java并发】—–J.U.C之并发工具类:CyclicBarrierCyclicBarrier,一个同步辅助类。它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
  16. 【死磕Java并发】—–J.U.C之并发工具类:CountDownLatchCountDownLatch 所描述的是”在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待“。用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。
  17. 【死磕Java并发】—–J.U.C之并发工具类:SemaphoreSemaphore,信号量,是一个控制访问多个共享资源的计数器。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。
  18. 【死磕Java并发】—–J.U.C之并发工具类:Exchanger可以在对中对元素进行配对和交换的线程的同步点。每个线程将条目上的某个方法呈现给 exchange 方法,与伙伴线程进行匹配,并且在返回时接收其伙伴的对象。Exchanger 可能被视为 SynchronousQueue 的双向形式。Exchanger 可能在应用程序(比如遗传算法和管道设计)中很有用。
  19. 【死磕Java并发】—–J.U.C之Java并发容器:ConcurrentHashMap ConcurrentHashMap 作为 Concurrent 一族,其有着高效地并发操作。在1.8 版本以前,ConcurrentHashMap 采用分段锁的概念,使锁更加细化,但是 1.8 已经改变了这种思路,而是利用 CAS + Synchronized 来保证并发更新的安全,当然底层采用数组+链表+红黑树的存储结构。这篇博客带你彻底理解 ConcurrentHashMap。
  20. 【死磕Java并发】—–J.U.C之ConcurrentHashMap红黑树转换分析在 1.8 ConcurrentHashMap 的put操作中,如果发现链表结构中的元素超过了TREEIFY_THRESHOLD(默认为8),则会把链表转换为红黑树,已便于提高查询效率。那么具体的转换过程是怎么样的?这篇博客给你答案。
  21. 【死磕Java并发】—–J.U.C之Java并发容器:ConcurrentLinkedQueueConcurrentLinkedQueue是一个基于链接节点的无边界的线程安全队列,它采用FIFO原则对元素进行排序。采用“wait-free”算法(即CAS算法)来实现的。CoucurrentLinkedQueue规定了如下几个不变性:1)在入队的最后一个元素的next为null。2)队列中所有未删除的节点的item都不能为null且都能从head节点遍历到。3)对于要删除的节点,不是直接将其设置为null,而是先将其item域设置为null(迭代器会跳过item为null的节点)。4)允许head和tail更新滞后。这是什么意思呢?意思就说是head、tail不总是指向第一个元素和最后一个元素(后面阐述)。
  22. 【死磕Java并发】—–J.U.C之Java并发容器:ConcurrentSkipListMap我们在Java世界里看到了两种实现key-value的数据结构:Hash、TreeMap,这两种数据结构各自都有着优缺点。Hash表:插入、查找最快,为O(1);如使用链表实现则可实现无锁;数据有序化需要显式的排序操作。红黑树:插入、查找为O(logn),但常数项较小;无锁实现的复杂性很高,一般需要加锁;数据天然有序。这里介绍第三种实现 key-value 的数据结构:SkipList。SkipList 有着不低于红黑树的效率,但是其原理和实现的复杂度要比红黑树简单多了。oncurrentSkipListMap 其内部采用 SkipLis 数据结构实现。
  23. 【死磕Java并发】—–J.U.C之阻塞队列:ArrayBlockingQueueArrayBlockingQueue,一个由数组实现的有界阻塞队列。该队列采用FIFO的原则对元素进行排序添加的。ArrayBlockingQueue 为有界且固定,其大小在构造时由构造函数来决定,确认之后就不能再改变了。ArrayBlockingQueue 支持对等待的生产者线程和使用者线程进行排序的可选公平策略,但是在默认情况下不保证线程公平的访问,在构造时可以选择公平策略(fair = true)。公平性通常会降低吞吐量,但是减少了可变性和避免了“不平衡性”。
  24. 【死磕Java并发】—–J.U.C之阻塞队列:PriorityBlockingQueuePriorityBlockingQueue是一个支持优先级的无界阻塞队列。默认情况下元素采用自然顺序升序排序,当然我们也可以通过构造函数来指定Comparator来对元素进行排序。需要注意的是PriorityBlockingQueue不能保证同优先级元素的顺序。
  25. 【死磕Java并发】—–J.U.C之阻塞队列:DelayQueueDelayQueue是一个支持延时获取元素的无界阻塞队列。里面的元素全部都是“可延期”的元素,列头的元素是最先“到期”的元素,如果队列里面没有元素到期,是不能从列头获取元素的,哪怕有元素也不行。也就是说只有在延迟期到时才能够从队列中取元素。DelayQueue主要用于两个方面:1)缓存:清掉缓存中超时的缓存数据。2)任务超时处理
  26. 【死磕Java并发】—–J.U.C之阻塞队列:SynchronousQueueSynchronousQueue与其他BlockingQueue有着不同特性:1)SynchronousQueue没有容量。与其他BlockingQueue不同,SynchronousQueue是一个不存储元素的BlockingQueue。每一个put操作必须要等待一个take操作,否则不能继续添加元素,反之亦然。2)因为没有容量,所以对应 peek, contains, clear, isEmpty ... 等方法其实是无效的。例如clear是不执行任何操作的,contains始终返回false,peek始终返回null。3)SynchronousQueue分为公平和非公平,默认情况下采用非公平性访问策略,当然也可以通过构造函数来设置为公平性访问策略(为true即可)。4|若使用 TransferQueue, 则队列中永远会存在一个 dummy node(这点后面详细阐述)。SynchronousQueue非常适合做交换工作,生产者的线程和消费者的线程同步以传递某些信息、事件或者任务。
  27. 【死磕Java并发】—–J.U.C之阻塞队列:LinkedTransferQueueLinkedTransferQueue 是基于链表的 FIFO 无界阻塞队列,它出现在 JDK7 中。Doug Lea 大神说 LinkedTransferQueue 是一个聪明的队列。它是 ConcurrentLinkedQueue、SynchronousQueue (公平模式下)、无界的LinkedBlockingQueues 等的超集。
  28. 【死磕Java并发】—–J.U.C之阻塞队列:LinkedBlockingDequeLinkedBlockingDeque 是一个由链表组成的双向阻塞队列,双向队列就意味着可以从对头、对尾两端插入和移除元素,同样意味着 LinkedBlockingDeque 支持 FIFO、FILO 两种操作方式。LinkedBlockingDeque 是可选容量的,在初始化时可以设置容量防止其过度膨胀,如果不设置,默认容量大小为 Integer.MAX_VALUE。
  29. 【死磕Java并发】—–深入分析ThreadLocalThreadLocal 提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。所以ThreadLocal与线程同步机制不同,线程同步机制是多个线程共享同一个变量,而ThreadLocal是为每一个线程创建一个单独的变量副本,故而每个线程都可以独立地改变自己所拥有的变量副本,而不会影响其他线程所对应的副本。可以说ThreadLocal为多线程环境下变量问题提供了另外一种解决思路。
  30. 【死磕Java并发】—–J.U.C之线程池:ThreadPoolExecutor鼎鼎大名的线程池。不需要多说!!!!!这篇博客深入分析 Java 中线程池的实现。
  31. 【死磕Java并发】—–J.U.C之线程池:ScheduledThreadPoolExecutorScheduledThreadPoolExecutor 是实现线程的周期、延迟调度的。ScheduledThreadPoolExecutor,继承 ThreadPoolExecutor 且实现了 ScheduledExecutorService 接口,它就相当于提供了“延迟”和“周期执行”功能的 ThreadPoolExecutor。在JDK API中是这样定义它的:ThreadPoolExecutor,它可另行安排在给定的延迟后运行命令,或者定期执行命令。需要多个辅助线程时,或者要求 ThreadPoolExecutor 具有额外的灵活性或功能时,此类要优于 Timer。 一旦启用已延迟的任务就执行它,但是有关何时启用,启用后何时执行则没有任何实时保证。按照提交的先进先出 (FIFO) 顺序来启用那些被安排在同一执行时间的任务。

三、优秀的线程专题博文

  1. ThreadLocal:https://juejin.im/post/5c805cb9f265da2d9e177f6d
  2. ThreadLocal:https://www.cnblogs.com/dolphin0520/p/3920407.html
  3. 3

四、部分问题

1.并行和并发有什么区别?
并发(concurrency)和并行(parallellism)
解释一:并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
解释二:并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
解释三:在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群
所以并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。
2.线程和进程的区别?
3.守护线程是什么?
4.创建线程有哪几种方式?:https://blog.csdn.net/u012501054/article/details/80384996
5.说一下 runnable 和 callable 有什么区别?:https://blog.csdn.net/u012501054/article/details/80384996
6.线程有哪些状态?
7.sleep() 和 wait() 有什么区别?
8.notify()和 notifyAll()有什么区别?
9.线程的 run()和 start()有什么区别?
10.创建线程池有哪几种方式?
11.线程池都有哪些状态?
12.线程池中 submit()和 execute()方法有什么区别?
13.在 java 程序中怎么保证多线程的运行安全?
14.多线程锁的升级原理是什么?
15.什么是死锁?
16.怎么防止死锁?
17.ThreadLocal 是什么?有哪些使用场景?
18.说一下 synchronized 底层实现原理?
19.synchronized 和 volatile 的区别是什么?
20.synchronized 和 Lock 有什么区别?
21.synchronized 和 ReentrantLock 区别是什么?
22.说一下 atomic 的原理?

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值