Java面试中的薪资跳板—高并发多线程(涨薪全靠它了!)

今天来和你们讨论一下并发多线程方面的知识,像死锁啊,生命周期啊,线程池啊,可重用啊都有涉及,但愿对你们有所帮助。java

前言:

身为一个博客博主,最近逛了一下圈子,发现好多大佬都在分享并发多线程方面的技术。今天咱也跟一下风,写一篇关于并发多线程方面的文章(主要是最近灵感枯竭不知道写啥哈哈),本篇文章由浅入深,主要是让你们可以清楚的认识他们,但愿对你们有所帮助,有什么意见或建议你们评论区里见。程序员

在这里插入图片描述

1.什么是线程?

线程是操做系统可以进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运做单位。程序员能够经过它进行多处理器编程,你可使用多线程对运算密集型任务提速。好比,若是一个线程完成一个任务要100毫秒,那么用十个线程完成改任务只需10毫秒。web

2.线程和进程有什么区别?

线程是进程的子集,一个进程能够有不少线程,每条线程并行执行不一样的任务。不一样的进程使用不一样的内存空间,而全部的线程共享一片相同的内存空间。每一个线程都拥有单独的栈内存用来存储本地数据。面试

3.如何在Java中实现线程?

两种方式:java.lang.Thread 类的实例就是一个线程可是它须要调用java.lang.Runnable接口来执行,因为线程类自己就是调用的Runnable接口因此你能够继承java.lang.Thread 类或者直接调用Runnable接口来重写run()方法实现线程。算法

4.Java 关键字volatile 与 synchronized 做用与区别?

1.volatile它所修饰的变量不保留拷贝,直接访问主内存中的。编程

在Java内存模型中,有main memory,每一个线程也有本身的memory (例如寄存器)。为了性能,一个线程会在本身的memory中保持要访问的变量的副本。这样就会出现同一个变 量在某个瞬间,在一个线程的memory中的值可能与另一个线程memory中的值,或者main memory中的值不一致的状况。 一个变量声明为volatile,就意味着这个变量是随时会被其余线程修改的,所以不能将它cache在线程memory中。缓存

2.synchronized安全

当它用来修饰一个方法或者一个代码块的时候,可以保证在同一时刻最多只有一个线程执行该段代码。数据结构

1、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程获得执行。另外一个线程必须等待当前线程执行完这个代码块之后才能执行该代码块。多线程

2、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另外一个线程仍然能够访问该object中的非synchronized(this)同步代码块。

3、尤为关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其余线程对object中全部其它synchronized(this)同步代码块的访问将被阻塞。

4、当一个线程访问object的一个synchronized(this)同步代码块时,它就得到了这个object的对象锁。结果,其它线程对该object对象全部同步代码部分的访问都被暂时阻塞。

5、以上规则对其它对象锁一样适用.

5.有哪些不一样的线程生命周期?

当咱们在Java程序中新建一个线程时,它的状态是New。当咱们调用线程的start()方法时,状态被改变为Runnable。线程调度器会为Runnable线程池中的线程分配CPU时间而且讲它们的状态改变为Running。其余的线程状态还有Waiting,Blocked 和Dead。

6.你对线程优先级的理解是什么?

每个线程都是有优先级的,通常来讲,高优先级的线程在运行时会具备优先权,但这依赖于线程调度的实现,这个实现是和操做系统相关的(OS dependent)。咱们能够定义线程的优先级,可是这并不能保证高优先级的线程会在低优先级的线程前执行。线程优先级是一个int变量(从1-10),1表明最低优先级,10表明最高优先级。

7.什么是死锁(Deadlock)?如何分析和避免死锁?

死锁是指两个以上的线程永远阻塞的状况,这种状况产生至少须要两个以上的线程和两个以上的资源。

分析死锁,咱们须要查看Java应用程序的线程转储。咱们须要找出那些状态为BLOCKED的线程和他们等待的资源。每一个资源都有一个惟一的id,用这个id咱们能够找出哪些线程已经拥有了它的对象锁。

避免嵌套锁,只在须要的地方使用锁和避免无限期等待是避免死锁的一般办法。

另外本人整理收藏了20年多家公司面试知识点整理 共127页的PDF 以及各类知识点整理 免费分享给你们,想要资料的话点击1065653031 暗号CSDN自行领取,或者私信我,暗号PDF。

8.什么是线程安全?Vector是一个线程安全类吗?

若是你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。若是每次运行结果和单线程运行的结果是同样的,并且其余的变量的值也和预期的是同样的,就是线程安全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的状况下也不会出现计算失误。很显然你能够将集合类分红两组,线程安全和非线程安全的。Vector 是用同步方法来实现线程安全的, 而和它类似的ArrayList不是线程安全的。

9.Java中如何中止一个线程?

Java提供了很丰富的API但没有为中止线程提供API。JDK 1.0原本有一些像stop(), suspend() 和 resume()的控制方法可是因为潜在的死锁威胁所以在后续的JDK版本中他们被弃用了,以后Java API的设计者就没有提供一个兼容且线程安全的方法来中止一个线程。当run() 或者 call() 方法执行完的时候线程会自动结束,若是要手动结束一个线程,你能够用volatile 布尔变量来退出run()方法的循环或者是取消任务来中断线程

10.什么是ThreadLocal?

ThreadLocal用于建立线程的本地变量,咱们知道一个对象的全部线程会共享它的全局变量,因此这些变量不是线程安全的,咱们可使用同步技术。可是当咱们不想使用同步的时候,咱们能够选择ThreadLocal变量。

每一个线程都会拥有他们本身的Thread变量,它们可使用get()\set()方法去获取他们的默认值或者在线程内部改变他们的值。ThreadLocal实例一般是但愿它们同线程状态关联起来是private static属性。

11.Sleep()、suspend()和wait()之间有什么区别?

Thread.sleep()使当前线程在指定的时间处于“非运行”(Not Runnable)状态。线程一直持有对象的监视器。好比一个线程当前在一个同步块或同步方法中,其它线程不能进入该块或方法中。若是另外一线程调用了interrupt()方法,它将唤醒那个“睡眠的”线程。

注意:sleep()是一个静态方法。这意味着只对当前线程有效,一个常见的错误是调用t.sleep(),(这里的t是一个不一样于当前线程的线程)。即使是执行t.sleep(),也是当前线程进入睡眠,而不是t线程。t.suspend()是过期的方法,使用suspend()致使线程进入停滞状态,该线程会一直持有对象的监视器,suspend()容易引发死锁问题。

object.wait()使当前线程出于“不可运行”状态,和sleep()不一样的是wait是object的方法而不是thread。调用object.wait()时,线程先要获取这个对象的对象锁,当前线程必须在锁对象保持同步,把当前线程添加到等待队列中,随后另外一线程能够同步同一个对象锁来调用object.notify(),这样将唤醒原来等待中的线程,而后释放该锁。基本上wait()/notify()与sleep()/interrupt()相似,只是前者须要获取对象锁。

12.什么是线程饿死,什么是活锁?

当全部线程阻塞,或者因为须要的资源无效而不能处理,不存在非阻塞线程使资源可用。JavaAPI中线程活锁可能发生在如下情形:

1,当全部线程在程序中执行Object.wait(0),参数为0的wait方法。程序将发生活锁直到在相应的对象上有线程调用Object.notify()或者Object.notifyAll()。

2,当全部线程卡在无限循环中。

13.什么是Java Timer类?如何建立一个有特定时间间隔的任务?

java.util.Timer是一个工具类,能够用于安排一个线程在将来的某个特定时间执行。Timer类能够用安排一次性任务或者周期任务。

java.util.TimerTask是一个实现了Runnable接口的抽象类,咱们须要去继承这个类来建立咱们本身的定时任务并使用Timer去安排它的执行。

14.Java中的同步集合与并发集合有什么区别?

同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更高。

在Java1.5以前程序员们只有同步集合来用且在多线程并发的时候会致使争用,阻碍了系统的扩展性。

Java5介绍了并发集合像ConcurrentHashMap,不只提供线程安全还用锁分离和 内部分区等现代技术提升了可扩展性。

15.同步方法和同步块,哪一个是更好的选择?

同步块是更好的选择,由于它不会锁住整个对象(固然你也可让它锁住整个对象)。同步方法会锁住整个对象,哪怕这个类中有多个不相关联的同步块,这一般会致使他们中止执行并须要等待得到这个对象上的锁。

16.什么是线程池? 为何要使用它?

建立线程要花费昂贵的资源和时间,若是任务来了才建立线程那么响应时间会变长,并且一个进程能建立的线程数有限。

为了不这些问题,在程序启动的时候就建立若干线程来响应处理,它们被称为线程池,里面的线程叫工做线程。

从JDK1.5开始,Java API提供了Executor框架让你能够建立不一样的线程池。好比单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合不少生存期短的任务的程序的可扩展线程池)。

17.Java中invokeAndWait 和 invokeLater有什么区别?

这两个方法是Swing API 提供给Java开发者用来从当前线程而不是事件派发线程更新GUI组件用的。InvokeAndWait()同步更新GUI组件,好比一个进度条,一旦进度更新了,进度条也要作出相应改变。若是进度被多个线程跟踪,那么就调用invokeAndWait()方法请求事件派发线程对组件进行相应更新。而invokeLater()方法是异步调用更新组件的。

18.多线程中的忙循环是什么?

忙循环就是程序员用循环让一个线程等待,不像传统方法wait(), sleep() 或 yield() 它们都放弃了CPU控制,而忙循环不会放弃CPU,它就是在运行一个空循环。这么作的目的是为了保留CPU缓存。

在多核系统中,一个等待线程醒来的时候可能会在另外一个内核运行,这样会重建缓存。为了不重建缓存和减小等待重建的时间就可使用它了。

19.Java内存模型是什么?

Java内存模型规定和指引Java程序在不一样的内存架构、CPU和操做系统间有肯定性地行为。它在多线程的状况下尤为重要。Java内存模型对一个线程所作的变更能被其它线程可见提供了保证,它们之间是先行发生关系。这个关系定义了一些规则让程序员在并发编程时思路更清晰。好比,先行发生关系确保了:

线程内的代码可以按前后顺序执行,这被称为程序次序规则。

对于同一个锁,一个解锁操做必定要发生在时间上后发生的另外一个锁定操做以前,也叫作管程锁定规则。

前一个对volatile的写操做在后一个volatile的读操做以前,也叫volatile变量规则。

一个线程内的任何操做必需在这个线程的start()调用以后,也叫做线程启动规则。

一个线程的全部操做都会在线程终止以前,线程终止规则。

一个对象的终结操做必需在这个对象构造完成以后,也叫对象终结规则。

可传递性

20.Java中interrupted 和isInterruptedd方法的区别?

interrupted() 和 isInterrupted()的主要区别是前者会将中断状态清除然后者不会。Java多线程的中断机制是用内部标识来实现的,调用Thread.interrupt()来中断一个线程就会设置中断标识为true。当中断线程调用静态方法Thread.interrupted()来检查中断状态时,中断状态会被清零。

非静态方法isInterrupted()用来查询其它线程的中断状态且不会改变中断状态标识。简单的说就是任何抛出InterruptedException异常的方法都会将中断状态清零。不管如何,一个线程的中断状态都有可能被其它线程调用中断来改变。

21.Java中的同步集合与并发集合有什么区别?

同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更高。在Java1.5以前程序员们只有同步集合来用且在多线程并发的时候会致使争用,阻碍了系统的扩展性。Java5介绍了并发集合像ConcurrentHashMap,不只提供线程安全还用锁分离和内部分区等现代技术提升了可扩展性。

无论是同步集合仍是并发集合他们都支持线程安全,他们之间主要的区别体如今性能和可扩展性,还有他们如何实现的线程安全上。

同步HashMap, Hashtable, HashSet, Vector, ArrayList 相比他们并发的实现(ConcurrentHashMap, CopyOnWriteArrayList, CopyOnWriteHashSet)会慢得多。形成如此慢的主要缘由是锁, 同步集合会把整个Map或List锁起来,而并发集合不会。并发集合实现线程安全是经过使用先进的和成熟的技术像锁剥离。

好比ConcurrentHashMap 会把整个Map 划分红几个片断,只对相关的几个片断上锁,同时容许多线程访问其余未上锁的片断。

一样的,CopyOnWriteArrayList 容许多个线程以非同步的方式读,当有线程写的时候它会将整个List复制一个副本给它。

若是在读多写少这种对并发集合有利的条件下使用并发集合,这会比使用同步集合更具备可伸缩性。

22.什么是线程池? 为何要使用它?

建立线程要花费昂贵的资源和时间,若是任务来了才建立线程那么响应时间会变长,并且一个进程能建立的线程数有限。为了不这些问题,在程序启动的时候就建立若干线程来响应处理,它们被称为线程池,里面的线程叫工做线程。从JDK1.5开始,Java API提供了Executor框架让你能够建立不一样的线程池。好比单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合不少生存期短的任务的程序的可扩展线程池)

线程池的做用,就是在调用线程的时候初始化必定数量的线程,有线程过来的时候,先检测初始化的线程还有空的没有,没有就再看当前运行中的线程数是否是已经达到了最大数,若是没有,就新分配一个线程去处理。

就像餐馆中吃饭同样,从里面叫一个服务员出来;但若是已经达到了最大数,就至关于服务员已经用尽了,那没得办法,另外的线程就只有等了,直到有新的“服务员”为止。

线程池的优势就是能够管理线程,有一个高度中枢,这样程序才不会乱,保证系统不会由于大量的并发而由于资源不足挂掉。

23.Java中活锁和死锁有什么区别?

活锁:一个线程一般会有会响应其余线程的活动。若是其余线程也会响应另外一个线程的活动,那么就有可能发生活锁。同死锁同样,发生活锁的线程没法继续执行。然而线程并无阻塞——他们在忙于响应对方没法恢复工做。这就至关于两个在走廊相遇的人:甲向他本身的左边靠想让乙过去,而乙向他的右边靠想让甲过去。可见他们阻塞了对方。甲向他的右边靠,而乙向他的左边靠,他们仍是阻塞了对方。

死锁:两个或更多线程阻塞着等待其它处于死锁状态的线程所持有的锁。死锁一般发生在多个线程同时但以不一样的顺序请求同一组锁的时候,死锁会让你的程序挂起没法完成任务。

24.如何避免死锁?

死锁的发生必须知足如下四个条件:

互斥条件:一个资源每次只能被一个进程使用。

请求与保持条件:一个进程因请求资源而阻塞时,对已得到的资源保持不放。

不剥夺条件:进程已得到的资源,在末使用完以前,不能强行剥夺。

循环等待条件:若干进程之间造成一种头尾相接的循环等待资源关系。

三种用于避免死锁的技术:

加锁顺序(线程按照必定的顺序加锁)

加锁时限(线程尝试获取锁的时候加上必定的时限,超过期限则放弃对该锁的请求,并释放本身占有的锁)

死锁检测

25.notify()和notifyAll()有什么区别?

1,notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。
2,void notify(): 唤醒一个正在等待该对象的线程。
3,void notifyAll(): 唤醒全部正在等待该对象的线程。
二者的最大区别在于:
notifyAll使全部原来在该对象上等待被notify的线程通通退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。

notify他只是选择一个wait状态线程进行通知,并使它得到该对象上的锁,但不惊动其余一样在等待被该对象notify的线程们,当第一个线程运行完毕之后释放对象上的锁,此时若是该对象没有再次使用notify语句,即使该对象已经空闲,其余wait状态等待的线程因为没有获得该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。

26.什么是可重入锁(ReentrantLock)?

Java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它容许把锁定的实现做为Java 类,而不是做为语言的特性来实现。这就为Lock 的多种实现留下了空间,各类实现可能有不一样的调度算法、性能特性或者锁定语义。 ReentrantLock 类实现了Lock ,它拥有与synchronized 相同的并发性和内存语义,可是添加了相似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用状况下更佳的性能。(换句话说,当许多线程都想访问共享资源时,JVM能够花更少的时候来调度线程,把更多时间用在执行线程上。)
Reentrant 锁意味着什么呢?简单来讲,它有一个与锁相关的获取计数器,若是拥有锁的某个线程再次获得锁,那么获取计数器就加1,而后锁须要被释放两次才能得到真正释放。这模仿了synchronized 的语义;若是线程进入由线程已经拥有的监控器保护的synchronized 块,就容许线程继续进行,当线程退出第二个(或者后续)synchronized块的时候,不释放锁,只有线程退出它进入的监控器保护的第一个synchronized 块时,才释放锁。

27.读写锁能够用于什么应用场景?

读写锁能够用于 “多读少写” 的场景,读写锁支持多个读操做并发执行,写操做只能由一个线程来操做
ReadWriteLock对向数据结构相对不频繁地写入,可是有多个任务要常常读取这个数据结构的这类状况进行了优化。ReadWriteLock使得你能够同时有多个读取者,只要它们都不试图写入便可。若是写锁已经被其余任务持有,那么任何读取者都不能访问,直至这个写锁被释放为止。
ReadWriteLock 对程序性能的提升主要受制于以下几个因素:
1,数据被读取的频率与被修改的频率相比较的结果。
2,读取和写入的时间
3,有多少线程竞争
4,是否在多处理机器上运行

总结:

如今的互联网公司都很重视高并发高可用技术,理论知识须要咱们去清楚理解,而最重要的仍是工做中所运用到的。那句话说的好,面试造火箭,工做拧螺丝,但愿你们都有造火箭的一天,那就说明你已经很牛皮了。其实我写了这么多,只是我本身的总结,并不必定适用于全部人,相信通过一些面试,你们都会有这些感触。

另外本人整理收藏了20年多家公司面试知识点整理 共127页的PDF 以及各类知识点整理 免费分享给你们,想要资料的话点击1065653031 暗号CSDN自行领取,或者私信我,暗号PDF。今天的分享就到这了,但愿你们多多支持我,一个不甘平凡的小码农!

在这里插入图片描述