前言
本来想着给自己放松一下,刷刷博客,突然被几道口试题难倒!什么是多线程中的上下文切换?什么是Daemon线程?它有什么意义?乐观锁和悲观锁的理解及怎样实现,有哪些实现方式?似乎有点模糊了,那就大概看一下口试题吧。好记性不如烂键盘
*** 12万字的java口试题整理 ***
*** java核心口试知识整理 ***
*** Java高频口试讲解视频(知识涵盖齐全) ***
什么是多线程中的上下文切换?
在上下文切换过程中,CPU会停止处置惩罚当前运行的程序,并保存当前程序运行的详细位置以便之后继续运行。从这个角度来看,上下文切换有点像我们同时阅读几本书,在来回切换书本的同时我们需要记住每本书当前读到的页码。
在程序中,上下文切换过程中的“页码”信息是保存在进程控制块(PCB)中的。PCB还经常被称作“切换桢”(switchframe)。“页码”信息会一直保存到CPU的内存中,直到他们被再次利用。
上下文切换是存储和恢复CPU状态的过程,它使得线程执行可以或许从中断点恢复执行。上下文切换是多任务操纵体系和多线程环境的根本特征。
什么是Daemon线程?它有什么意义?
所谓后台(daemon)线程,也叫保卫线程,是指在程序运行的时候在后台提供一种通用服务的线程,而且这个线程并不属于程序中不可或缺的部分。
因此,当全部的非后台线程结束时,程序也就终止了,同时会杀死进程中的全部后台线程。反过来说, 只要有任何非后台线程还在运行,程序就不会终止。
必须在线程启动之前调用setDaemon()方法,才能把它设置为后台线程。注意:后台进程在不执行finally子句的情况下就会终止其run()方法。
比如:JVM的垃圾回收线程就是Daemon线程,Finalizer也是保卫线程。
乐观锁和悲观锁的理解及怎样实现,有哪些实现方式?
悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操纵之前先上锁。再比如Java内里的同步原语synchronized关键字的实现也是悲观锁。
乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以利用版本号等机制。
乐观锁实用于多读的应用范例,这样可以进步吞吐量,像数据库提供的类似于write_condition机制,实在都是提供的乐观锁。
在Java中java.util.concurrent.atomic包下面的原子变量类就是利用了乐观锁的一种实现方式CAS实现的。
乐观锁的实现方式:
1、利用版本标识来确定读到的数据与提交时的数据是否一致。提交后修改版本标识,不一致时可以采取丢弃和再次尝试的策略。
2、java中的Compare and Swap即CAS ,当多个线程尝试利用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。
CAS 操纵中包含三个操纵数 —— 需要读写的内存位置(V)、进行比较的预期原值(A)和拟写入的新值(B)。假如内存位置V的值与预期原值A相匹配,那么处置惩罚器会自动将该位置值更新为新值B。否则处置惩罚器不做任何操纵。
CAS缺点:
- ABA问题:比如说一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出
A,而且two进行了一些操纵变成了B,然后two又将V位置的数据变成A,这时候线程one进行
CAS操纵发现内存中仍然是A,然后one操纵成功。尽管线程one的CAS操纵成功,但大概存在
潜藏的问题。从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference来解决
ABA问题。
- 循环时间长开销大:对于资源竞争严重(线程冲突严重)的情况,CAS自旋的概率会比较大,
从而浪费更多的CPU资源,服从低于synchronized。
- 只能保证一个共享变量的原子操纵:当对一个共享变量执行操纵时,我们可以利用循环CAS的方式来保证原子操纵,但是对多个共享变量操纵时,循环CAS就无法保证操纵的原子性,这个时候就可以用锁。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |