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关于同步的规定:

  1. 线程解锁前,必须把共享变量的值刷新回在主内存;
  2. 线程加锁前,必须读取主内存的最新值到自己的工作内存;
  3. 加锁解锁是同一把锁;

2. 介绍一下violated

定义:是java虚拟机提供的轻量级的同步机制;

特征:

  1. 保证可见性;

    JVM保证每次写后会立即同步回主内存;

  2. 不保证原子性;

  3. 禁止指令重排序;

    JVM保证在violate变量写入后的代码肯定不会出现在写入前执行; 有volatile修饰的变量赋值后,字节码多了一个lock add$0x0, (%esp)(空操作),该操作相当于内存屏障,重排序时不能将后面的指令重排序到内存屏障中前的位置。多的指令由于IA32规范中规定lock前缀不允许使用nop指令,该指令的作用是将本处理器缓存写入内存,该动作引起别的处理器或者别的内核无效化其缓存,这种操作相当于对缓存中的变量做了一次类似store和write操作,可以使volatile变量的修改对其他处理器立即可见。

3. 写一个单例模式

DCL双端检锁机制不一定线程安全,可能出现指令重排序,加入violate可以避免重排序。例如单例下new一个对象需要进行以下3步:

  1. 分配对象内存空间;

  2. 初始化对象;

    1. 将引用指向内存地址;

    步骤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的问题

  1. 长时间不成功,会造成自旋导致CPU带来很大的开销;

  2. 只能保证一个共享变量的操作;

  3. 出现ABA问题;

    如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然为A值,不能说明它的值没有被其他线程改变过。因为可能他在这段期间被改为了B后来又改回A。如果遇到此问题,使用互斥同步来处理或者AtomicStampedReference原子更新引用;

6. ArrayList线程不安全的替换方案

  1. 使用Vector

  2. 使用集合类方法Collections.synchronizedList()

    1.SynchronizedList有很好的扩展和兼容功能。他可以将所有的List的子类转成线程安全的类;

    2.使用SynchronizedList的时候,进行遍历时要手动进行同步处;

    3.SynchronizedList可以指定锁定的对象;

  3. 使用CopyOnWriteList,写时复制容器;

    在往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先加锁将数组复制一份(len+1),往新的数组中增加一个,然后再将原容器引用指向新容器,解锁。这样做的好处是可以并发的读,读写可以分离的思想,读和写是对不同的数组进行操作。

7. 什么是公平锁

概念:在并发包中ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁或非公平锁,默认是非公平锁;

公平锁:在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果空,或者是队列首个就占有锁,否则就加入等待队列中,按照FIFO的规则获取锁;

非公平锁:先抢先得,否则就排队等待。 优点吞吐量大。synchronized也是非公平的。

8. 什么是可重入锁

指的是同一线程外层函数获得锁之后,内层递归函数仍然能获取该锁的代码,在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。加几次锁需要释放几次锁,否则死锁。synchronized, ReentrantLock都是可重入锁。

synchronized:java中最基本的互斥同步手段。javac编译后,会在同步块前后形成monitorentermonitorexit这两个字节码指令;如果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锁相关面试题总结(一)相关推荐

  1. MySQL锁相关面试题

    对MySQL的锁了解吗? 当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制. 例子:就像酒店的房间,如果大家随意进出,就会出现多人抢夺一个 ...

  2. java工程师面试题大全100%公司笔试题你都能碰到几个

    1.  hibernate中离线查询去除重复项怎么加条件??? dc.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 2.  http协议及端 ...

  3. java程序设计试题_《Java语言程序设计》期末考试模拟试题——填空题和编程题...

    一.根据题意,填写出空格中的内容 Java平台包括三个技术方向,其中J2ME代表____________.J2SE代表___________.J2EE代表____________.2.面向对象的四大概 ...

  4. hibernate savealiasentity 保存后id为空_好程序员Java教程分享Java面试题之Hibernate

    好程序员Java教程分享Java面试题之Hibernate 1.简书一下Hibernated的开发流程 第一步:加载Hibernate的配置文件,读取配置文件的参数, 第二步:创建SessionFac ...

  5. java 核桃的数量,[Java教程]【蓝桥杯】历届试题 核桃的数量

    [Java教程][蓝桥杯]历届试题 核桃的数量 0 2016-03-31 23:33:50 历届试题 核桃的数量 时间限制:1.0s   内存限制:256.0MB问题描述 小张是软件项目经理,他带领3 ...

  6. java biginteger位数,Java之BigInteger(面试题12:打印1到最大的n位数)

    1.  以<剑指offer 名企面试官精讲典型编程题> - 面试题12:打印1到最大的n位数为例. 题目内容如下: 输入数字n,按顺序打印出从1到最大的n位十进制数. 比如输入3,则打印出 ...

  7. java doubke类型转换为String_Java基础知识面试题大集合

    本文整理自作者:ThinkWon  链接: blog.csdn.net/ThinkWon/article/details/104390612 本文知识点目录 Java概述 何为编程 什么是Java j ...

  8. 此异常最初是在此调用堆栈中引发的:_【8】进大厂必须掌握的面试题Java面试异常和线程...

    点击上方"全栈程序员社区",星标公众号 重磅干货,第一时间送达 Q1.错误和异常有什么区别? 错误是在运行时发生的不可恢复的情况.如OutOfMemory错误.这些JVM错误无法在 ...

  9. java程序运行结果题_2016年关于Java编程与程序运行结果笔试题

    2016年关于Java编程与程序运行结果笔试题 1.Java编程,打印昨天的当前时刻 public class YesterdayCurrent{ public void main(String[] ...

最新文章

  1. linux中文件记录的时间参数,【Linux】stat命令查看文件的三个时间参数
  2. 【Git】git使用 - 各种常用场景命令解决
  3. 1.12 梯度的数值逼近-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授
  4. 来自朋友最近阿里、腾讯、美团等P7岗位面试题
  5. 虚函数和虚析构函数的实现原理--虚函数表
  6. swiper教程--swiper的基础使用(二十)
  7. 此行向远:他们为人工智能雕刻灵魂
  8. SAS Marketing Automation 6.3 User’s Guide 学习笔记
  9. python爬取去哪儿网机票_去哪儿网机票爬虫
  10. linux51单片机烧录程序,单片机成长之路(51基础篇) - 006 在Linux下搭建51单片机的开发烧写环境...
  11. pip 如何设置代理
  12. 万物互联时代到来,锐捷发布场景化无线零漫游方案
  13. Redis的底层数据结构----快速列表_quicklist
  14. Ubuntu 16.04 修改软件更新源地址
  15. Win10 提示你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证的来宾访问
  16. Android开发实现高德地图定位详解
  17. java实现定时任务 schedule_Java定时任务调度详解
  18. 蓝鸽集团c++开发工程师笔试题
  19. js html监听ctrl v,如何使用JavaScript检测Ctrl+V,Ctrl+C?
  20. 每日一题-45(访问日期之间最大的空档期)

热门文章

  1. 酷Q插件_SDK———入门与使用
  2. 第2关:求解出n以内所有能被5整除的正整数的乘积-------C语言程序设计技术(循环结构程序设计1)
  3. Git详解之必知点----Git、本地仓库、远程仓库、IDEA集成Git
  4. PHP使用web3还原助记词
  5. git设置master权限_Gitlab权限管理
  6. 联想lenovo sl700 240G sata ps3111主控+未知颗粒 掉盘,ps3111写保护开卡量产修复过程
  7. FCN网络(Fully Convolutional Networks for Semantic Segmentation)
  8. pythonopencv人脸识别考勤_Python+Opencv+Tkinter指纹识别与人脸识别的门禁兼考勤(一)...
  9. Docker容器热迁移技术(基于CRIU实现)
  10. 输入相应的数打印三角形