JAVA面试题|JAVA锁相关面试题总结(一)
JAVA基础篇面试题
文章目录
- JAVA基础篇面试题
- 1. 什么是JMM
- 2. 介绍一下violated
- 3. 写一个单例模式
- 4. 介绍一下CAS
- 5. CAS的问题
- 6. ArrayList线程不安全的替换方案
- 7. 什么是公平锁
- 8. 什么是可重入锁
- 9. 什么是自旋锁
- 10. 什么是独占/共享/互斥锁
- 11. CountDownLatch,CyclicBarrier,Semaphore
- 12. 什么是阻塞队列
1. 什么是JMM
JMM(Java Memory Model)本身是一种抽象的概念并不真实存在,它描述的是一组规则或规范,通过这组规定定义了程序中各个变量(实例字段,静态字段和构成数组对象的元素)的访问方式;
JMM关于同步的规定:
- 线程解锁前,必须把共享变量的值刷新回在主内存;
- 线程加锁前,必须读取主内存的最新值到自己的工作内存;
- 加锁解锁是同一把锁;
2. 介绍一下violated
定义:是java虚拟机提供的轻量级的同步机制;
特征:
保证可见性;
JVM保证每次写后会立即同步回主内存;
不保证原子性;
禁止指令重排序;
JVM保证在violate变量写入后的代码肯定不会出现在写入前执行; 有volatile修饰的变量赋值后,字节码多了一个
lock add$0x0, (%esp)
(空操作),该操作相当于内存屏障,重排序时不能将后面的指令重排序到内存屏障中前的位置。多的指令由于IA32规范中规定lock前缀不允许使用nop指令,该指令的作用是将本处理器缓存写入内存,该动作引起别的处理器或者别的内核无效化其缓存,这种操作相当于对缓存中的变量做了一次类似store和write操作,可以使volatile变量的修改对其他处理器立即可见。
3. 写一个单例模式
DCL双端检锁机制不一定线程安全,可能出现指令重排序,加入violate可以避免重排序。例如单例下new一个对象需要进行以下3步:
分配对象内存空间;
初始化对象;
- 将引用指向内存地址;
步骤2和步骤3不存在依赖关系,可以重排序;
因此DCL应该如此实现:
class SingletonDemo {private static violate SingletonDemo instance = null;public static SingletonDemo getInstance() {if (instance == null) {synchronized(SingletonDemo.class) {if (instance == null) {instance = new SingletonDemo();}}}return instance;} }
4. 介绍一下CAS
概念:compare and set。需要3个操作数,分别是内存位置V,旧的预期值A,准备设置的新值B。CAS执行时,当地址V对应的旧值是A时,处理器才会将V对应的值更新为B,否则就不执行更新。该操作为原子操作,不会被其他线程中断;
Java的实现:引入Unsafe
类,其通过本地native方法直接操作特定的内存数据。通过对内存的偏移地址去获取值和循环修改数据直至成功。JVM会编译成CAS的字节码指令,通过硬件功能保证指令执行过程中是连续的,原子性的。
public class AtomicInteger extends Number implements java.io.Serializable {// setup to use Unsafe.compareAndSwapInt for updatesprivate static final Unsafe unsafe = Unsafe.getUnsafe();// 获取对象值的内存偏移量private static final long valueOffset; static {try {valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}// 此处要设置为violatileprivate volatile int value;// ......
}
5. CAS的问题
长时间不成功,会造成自旋导致CPU带来很大的开销;
只能保证一个共享变量的操作;
出现ABA问题;
如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然为A值,不能说明它的值没有被其他线程改变过。因为可能他在这段期间被改为了B后来又改回A。如果遇到此问题,使用互斥同步来处理或者
AtomicStampedReference
原子更新引用;
6. ArrayList线程不安全的替换方案
使用Vector
使用集合类方法
Collections.synchronizedList()
1.SynchronizedList有很好的扩展和兼容功能。他可以将所有的List的子类转成线程安全的类;
2.使用SynchronizedList的时候,进行遍历时要手动进行同步处;
3.SynchronizedList可以指定锁定的对象;
使用CopyOnWriteList,写时复制容器;
在往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先加锁将数组复制一份(len+1),往新的数组中增加一个,然后再将原容器引用指向新容器,解锁。这样做的好处是可以并发的读,读写可以分离的思想,读和写是对不同的数组进行操作。
7. 什么是公平锁
概念:在并发包中ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁或非公平锁,默认是非公平锁;
公平锁:在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果空,或者是队列首个就占有锁,否则就加入等待队列中,按照FIFO的规则获取锁;
非公平锁:先抢先得,否则就排队等待。 优点吞吐量大。synchronized
也是非公平的。
8. 什么是可重入锁
指的是同一线程外层函数获得锁之后,内层递归函数仍然能获取该锁的代码,在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。加几次锁需要释放几次锁,否则死锁。synchronized, ReentrantLock都是可重入锁。
synchronized
:java中最基本的互斥同步手段。javac
编译后,会在同步块前后形成monitorenter
和monitorexit
这两个字节码指令;如果synchronized
指明了对象参数,那就锁定这个对象;如果未指定对象参数,则根据其修饰的方法类型(实例方法,或类方法)来决定是取代码所在的对象实例还是取类型对应的Class对象来作为线程要持有的锁。
具体的执行过程需要看[java基础知识-java内部的锁]文章,简述一下加锁解锁原理:
实现:每个锁对象头有一个锁的计数器,和一个指向持有锁的线程的指针;
原理:目标锁对象的计数器为0时,线程monitorenter
将其占有,并计数器+1,每次加锁(重入时)计数器+1,当monitorexit
退出时,计数器-1。当计数器为0时,表示锁已释放;
9. 什么是自旋锁
是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。
10. 什么是独占/共享/互斥锁
多个线程同时读一个资源类没有任何问题,所以为了满足开发量,读取共享资源应该可以同时进行,但是,如果有一个线程写共享资源,其他线程就无法读写。
class Cache {private volatile Map<String, Object> map = new HashMap<>();private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();public Object get(String key) {lock.readLock().lock();System.out.println(String.format("线程%s 读取开始", Thread.currentThread().getName()));try {Object o = map.get(key);return o;}finally {System.out.println(String.format("线程%s 读取结束", Thread.currentThread().getName()));lock.readLock().unlock();}}public void set(String key, Object v) {lock.writeLock().lock();System.out.println(String.format("线程%s 写开始", Thread.currentThread().getName()));try {map.put(key, v);} finally {System.out.println(String.format("线程%s 写结束", Thread.currentThread().getName()));lock.writeLock().unlock();}}
}
11. CountDownLatch,CyclicBarrier,Semaphore
CountDownLatch递减,直到为0才不阻塞;
CyclicBarrier递增,直到预期值才不阻塞;
Semaphore信号量,同时可进入临界区线程数量;
Semaphore s = new Semaphore(3);// 同时允许三个线程访问
s.acquire();
s.release();
12. 什么是阻塞队列
特征:BlockingQueue 阻塞队列,当阻塞队列是空时,从队列中获取元素的操作将会被阻塞,当阻塞队列是空时,从队列中获取元素的操作将会被阻塞。
优势:在多线程环境下,我们必须自己取控制这些资源管理的细节,尤其还要兼顾效率和线程安全,而这会给我们的程序带来不小的复杂度。
实现类:
ArrayBlockQueue
:由数组结构组成的有界阻塞队列LinkedBlockingQueue
:由链表结构组成的有界(但是默认大小 Integer.MAX_VALUE)的阻塞队列- 有界,但是界限非常大,相当于无界,可以当成无界
- PriorityBlockQueue:支持优先级排序的无界阻塞队列
- DelayQueue:使用优先级队列实现的延迟无界阻塞队列
SynchronousQueue
:不存储元素的阻塞队列,也即单个元素的队列- 生产一个,消费一个,不存储元素,不消费不生产
- LinkedTransferQueue:由链表结构组成的无界阻塞队列
- LinkedBlockingDeque:由链表结构组成的双向阻塞队列
核心方法:
抛出异常 | 当阻塞队列满时:在往队列中add插入元素会抛出 IIIegalStateException:Queue full 当阻塞队列空时:再往队列中remove移除元素,会抛出NoSuchException |
---|---|
特殊性 | 插入方法,成功true,失败false 移除方法:成功返回出队列元素,队列没有就返回空 |
一直阻塞 | 当阻塞队列满时,生产者继续往队列里put元素,队列会一直阻塞生产线程直到put数据or响应中断退出, 当阻塞队列空时,消费者线程试图从队列里take元素,队列会一直阻塞消费者线程直到队列可用。 |
超时退出 | 当阻塞队列满时,队里会阻塞生产者线程一定时间,超过限时后生产者线程会退出 |
JAVA面试题|JAVA锁相关面试题总结(一)相关推荐
- MySQL锁相关面试题
对MySQL的锁了解吗? 当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制. 例子:就像酒店的房间,如果大家随意进出,就会出现多人抢夺一个 ...
- java工程师面试题大全100%公司笔试题你都能碰到几个
1. hibernate中离线查询去除重复项怎么加条件??? dc.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 2. http协议及端 ...
- java程序设计试题_《Java语言程序设计》期末考试模拟试题——填空题和编程题...
一.根据题意,填写出空格中的内容 Java平台包括三个技术方向,其中J2ME代表____________.J2SE代表___________.J2EE代表____________.2.面向对象的四大概 ...
- hibernate savealiasentity 保存后id为空_好程序员Java教程分享Java面试题之Hibernate
好程序员Java教程分享Java面试题之Hibernate 1.简书一下Hibernated的开发流程 第一步:加载Hibernate的配置文件,读取配置文件的参数, 第二步:创建SessionFac ...
- java 核桃的数量,[Java教程]【蓝桥杯】历届试题 核桃的数量
[Java教程][蓝桥杯]历届试题 核桃的数量 0 2016-03-31 23:33:50 历届试题 核桃的数量 时间限制:1.0s 内存限制:256.0MB问题描述 小张是软件项目经理,他带领3 ...
- java biginteger位数,Java之BigInteger(面试题12:打印1到最大的n位数)
1. 以<剑指offer 名企面试官精讲典型编程题> - 面试题12:打印1到最大的n位数为例. 题目内容如下: 输入数字n,按顺序打印出从1到最大的n位十进制数. 比如输入3,则打印出 ...
- java doubke类型转换为String_Java基础知识面试题大集合
本文整理自作者:ThinkWon 链接: blog.csdn.net/ThinkWon/article/details/104390612 本文知识点目录 Java概述 何为编程 什么是Java j ...
- 此异常最初是在此调用堆栈中引发的:_【8】进大厂必须掌握的面试题Java面试异常和线程...
点击上方"全栈程序员社区",星标公众号 重磅干货,第一时间送达 Q1.错误和异常有什么区别? 错误是在运行时发生的不可恢复的情况.如OutOfMemory错误.这些JVM错误无法在 ...
- java程序运行结果题_2016年关于Java编程与程序运行结果笔试题
2016年关于Java编程与程序运行结果笔试题 1.Java编程,打印昨天的当前时刻 public class YesterdayCurrent{ public void main(String[] ...
最新文章
- linux中文件记录的时间参数,【Linux】stat命令查看文件的三个时间参数
- 【Git】git使用 - 各种常用场景命令解决
- 1.12 梯度的数值逼近-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授
- 来自朋友最近阿里、腾讯、美团等P7岗位面试题
- 虚函数和虚析构函数的实现原理--虚函数表
- swiper教程--swiper的基础使用(二十)
- 此行向远:他们为人工智能雕刻灵魂
- SAS Marketing Automation 6.3 User’s Guide 学习笔记
- python爬取去哪儿网机票_去哪儿网机票爬虫
- linux51单片机烧录程序,单片机成长之路(51基础篇) - 006 在Linux下搭建51单片机的开发烧写环境...
- pip 如何设置代理
- 万物互联时代到来,锐捷发布场景化无线零漫游方案
- Redis的底层数据结构----快速列表_quicklist
- Ubuntu 16.04 修改软件更新源地址
- Win10 提示你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证的来宾访问
- Android开发实现高德地图定位详解
- java实现定时任务 schedule_Java定时任务调度详解
- 蓝鸽集团c++开发工程师笔试题
- js html监听ctrl v,如何使用JavaScript检测Ctrl+V,Ctrl+C?
- 每日一题-45(访问日期之间最大的空档期)
热门文章
- 酷Q插件_SDK———入门与使用
- 第2关:求解出n以内所有能被5整除的正整数的乘积-------C语言程序设计技术(循环结构程序设计1)
- Git详解之必知点----Git、本地仓库、远程仓库、IDEA集成Git
- PHP使用web3还原助记词
- git设置master权限_Gitlab权限管理
- 联想lenovo sl700 240G sata ps3111主控+未知颗粒 掉盘,ps3111写保护开卡量产修复过程
- FCN网络(Fully Convolutional Networks for Semantic Segmentation)
- pythonopencv人脸识别考勤_Python+Opencv+Tkinter指纹识别与人脸识别的门禁兼考勤(一)...
- Docker容器热迁移技术(基于CRIU实现)
- 输入相应的数打印三角形