多线程知识点总结(更新中..)

多线程的基础

1.线程的生命周期?(五个)
一个线程经历了新建、就绪、阻塞、运行、死亡五个生命周期。当一个线程被创建时,即为“新建”阶段,调用了该线程的start
()方法之后,就进入了“就绪”阶段。若线程抢到了CPU的执行权,就会进入“运行”阶段,在“运行”阶段的线程被调用了
yield()方法之后就会回到“就绪”阶段。在“运行”阶段的线程被调用了sleep()/wait()/suspend()/join()之后,就进入了“阻
塞”阶段,而通过sleep()时间到/被另一个线程notify或者notifyAll之后/resume()/join()进来的线程执行完毕之后,就
可以从“阻塞”状态中恢复过来,回到了“就绪”状态。当一个线程执行完毕之后或者在执行过程中抛出了异常,走到了生命周期
的终点--“死亡”状态。


2.多线程的状态?(六个)
六个状态包括了:
NEW:线程被创建完成后,再调用了其start()方法,就进入的此状态
RUNNING:当多个线程准备争抢CPU的执行权时,就进入了RUNNING状态
BLOCKED:当其中一个线程抢占到了排它锁,其他的线程就会进入BLOCKED状态
WAITING:被执行了wait()方法的线程将进入无限期的等待状态,需要另一个线程将其唤醒才能离开这一状态
TIMED_WAITED:被执行了sleep()方法的线程将进入有限期的等待状态,睡眠的时间一到,就会离开此状态
TERMINATED:线程执行完毕之后,就进入了TERMINATED状态


3.线程间的通信问题?
线程间通信的前提是Synchronized,Synchronized保证了不同线程之间的排他性和可见性
①只有加了锁之后,才能使用wait()方法
②wait()方法能够被其他线程的notify()唤醒
③调用了notify()之,阻塞的线程不会被立即唤醒,只有当前线程释放锁资源之后,才能被唤醒
④从wait()方法返回的前提是释放了锁资源


4.sleep()和wait()的区别?
①sleep()是Thread类的方法;而wait()是Object类的方法
②sleep()是想睡就睡;而wait()方法只有在加锁之后才可以被调用
③sleep()执行之后,不会释放锁资源;而wait()执行之后,会释放锁资源
④sleep()等待一定的时间之后,线程脱离阻塞状态;而被wait()的线程必须等待另一个线程将其显式地唤醒


5.线程的启动方法有哪些?区别?实现Runnable和继承Thread哪种方法更好?
线程启动方式有四种
①继承Thread
②实现Runnable
③实现Callable(有返回值)
④线程池
实现Runnable的方法要比Thread的方式更好。原因:1)java是单继承,多实现的 2)实现方法可以操纵同一份共享资源


6.线程安全问题如何解决?
同步方法或者同步代码块,Lock锁


7.类锁和对象锁?
静态的同步方法/块持有的就是类锁,非静态的同步方法/块持有的就是对象锁。不同的对象就会有不同的对象锁,类锁只有一把。
线程八锁的例子,了解一下,理解更透彻。


JUC

1.JMM模型?

一个内存模型描述了一个给定的程序和和它的执行路径是否是一个合法的执行路径。对于java与言来说,内存模型通过考察在程序执行路径中每一个读操作,根据特定的规则,检查写操作对应的读操作是否能是有效的。

java内存模型只是定义了一个规范,具体的实现可以是根据实际情况自由实现的。但是实现要满足java内存模型定义的规范。

(一个主内存,每个线程都具有自己的工作内存。执行读写操作时,线程总是会把共享变量拷贝到自己的工作空间中,不同线程的工作空间是内存不可见的。)


2.为什么出现了线程不安全的问题?
重排序破坏了多线程程序的语义


3.说说volatile关键字?
volatile是较Synchronized更轻量级的锁。用它来修饰一个变量,表示了该变量是易变、容易被修改的。volatile增加的变量的内
存可见性。volatile的happens-before规则(对volatile变量的读要先于对volatile变量的上一次写,永远读到最新的值)决定它
的内存语义有:1)当对一个volatile变量进行写操作时,JMM会把该线程对应的工作内存中的共享变量刷新到主内存中。 2)当对
一个volatile变量进行读操作时,JMM会把该线程对应的工作内存中的该变量置为无效,线程将从主内存中读取共享变量。
volatile变量具有内存可见性,但是对该变量的操作不具有原子性。


4.说说CAS算法?
CompareAndSwap。CAS是一种无锁的非阻塞算法。CAS有三个操作数,内存中的值V,旧的预期值A,更新后的值B,每次比较V和A的
值是否相同,若相同,则实现更新并将B的值刷新到主存中去;若不相同,则自旋反复执行CAS,直至满足CAS算法。


3.为什么HashMap是线程不安全的?为什么HashTable效率低下?
HashMap是数组+链表/红黑树的结构。多线程时,当在数组中插入值时,后一线程将会覆盖前一线程的值,同理,在链表中的插入
也是有这样的问题。
HashTable是数组+链表的结构。每次插入操作都会锁整张表,并不适合并发操作。
解决办法就是使用CurrentHashMap。


4.CurrentHashMap如何保证线程安全?
CurrentHashMap使用了锁分段机制,每次hash都首先会定位到不同的segment,执行插入操作时,只会对段进行加锁,而在不同段
中的插入互补影响。不仅保证线程安全,还有着很高的并发效率。


5.解释一下CurrentHashMap的get()/put()/size()方法
源码。。。硬伤


6.Fork()/Join()框架了解吗?工作窃取算法了解吗?
该框架将一个大的任务分割成许多的小任务(分割到达到阈值条件时不再分割),将小任务的执行结果又合并起来,最终返回大任
务的结果。
工作窃取算法是指:当使用Fork/Join框架时。通常任务队列都会使用双端队列,执行任务时,就从双端队列的队头拿取任务;窃
取任务就发生在队尾,当一个线程执行完自身的任务时,就会从另外的线程的队尾窃取任务来做,这样就提高了并发执行的效率。


7.Fork()/Join()如何使用?
继承任务类RecursiveAction或者RecursiveTask,并覆盖其compute方法,在测试方法中,首先创建一个ForkJonPool,并将任务对
象的实例submit到池中去,返回一个Future的类型的变量。通过该变量的get方法返回任务的结果。


8.Atomic包了解吗?
为我们提供了许多类来支持并发更新操作。有原子类型类、原子数组类、原子引用类、原子字段类。
多线程环境下,当我们更新一个int变量时,如执行变量的i++这样的原子操作时,可能会得到不是我们期望的值,引发了线程安全
的问题,通常使用synchronized来保证线程安全,但是这种做发消耗的资源很大,而用volatile来修饰变量时,却不能保证这种复
合操作的原子性。因此,实现了CAS的Atomic是最好的选择。


9.AtomicInteger如何保证原子性?
AtomicInteger类中的api都是通过实现了CAS算法来保证原子性的。对变量进行更新时,都会循环的执行CAS操作。


10.AtomicBoolean是如何实现的?
Unsafe包中只为我们提供了三种CAS方法,没有针对Boolean的方法,其实是先把Boolean类型的变量转换成整型的,再用对整形变
量的CAS方法去处理的!对于其他类来说,道理都是相通的。

11.Java中的并发工具类有哪些?
CountLatch(闭锁)、CyclicBarrier(循环屏障)、Semaphore(控制并发线程数)、Exchanger(线程间交换数据)


12.说说CountDownLatch和CyclicBarrier的区别?
》相同点:
①这两者作用有点相似,如果能够设计得当,都可以用于阻隔不同的线程
②闭锁不会阻隔await()之前的普通线程;屏障不会阻隔没有调用await()方法的线程
》不同点:
①前者减计数;后者加计数
②前者不可重复利用;后者可以循环使用(reset())
③应用的场景不同

13.Semaphore了解?
在同一段时间内,控制并发线程的数量为有限个。
在操作共享变量的方法前,加上acquire()能够获得一个许可证;在操作之后加上一个release()能够归还许可证。

14.为什么使用线程池?
减少因为创建和销毁线程而导致的开销,提高响应的速度。

15.线程池ThreadPoolExecutor的实现原理?画出模型图?
主线程中execute()/submit()任务到线程池中
1)当线程池中运行着的线程数量不超过corepoolsize的时候,则会创建一个新的线程来执行任务(此时,需要获得全局锁)。即使线程池中有空闲的线程,也会创建新的线程,只有当大于corepoolsize时不再创建新的线程。
2)渐渐地,线程中运行的线程大于等于corepoolsize,会将任务加入到阻塞队列中去,只有等到线程池中有线程被执行完毕时,线程池会从阻塞队列中take任务出来处理。
3)阻塞队列也分为有界和无界的。若是无界的,会一直加入到阻塞队列中,直到内存被塞满。若是有界的,当阻塞队列也满时,而线程池中的运行着的线程数量大于等于corepoolsize且不超过maxpoolsize,则继续在线程池中创建线程处理任务
4)如果创建线程时将使得当前线程数量超过maxpoolsize,name就会触发饱和策略,一般是任务被拒绝


16.向线程池中提交任务的方式有几种?说说区别?
execute()和submit()两种。有无Future类型返回值的区别


17.Lock与Synchronized的区别?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值