并发-Java 并发进阶常见面试题总结

目录

1. synchronized 关键字

双重校验锁实现对象单例(线程安全)

1.3 讲一下 synchronized 关键字的底层原理

1.4 说说 JDK1.6 之后的synchronized 关键字底层做了哪些优化,可以详细介绍一下这些优化吗

1.5. 谈谈 synchronized和ReentrantLock 的区别

2. volatile关键字

3. ThreadLocal

4. 线程池

4.1. 为什么要用线程池?

4.3. 执行execute()方法和submit()方法的区别是什么呢?

5. Atomic 原子类

6. AQS

使用


1. synchronized 关键字

双重校验锁实现对象单例(线程安全)

public class Singleton {

    private volatile static Singleton uniqueInstance;

    private Singleton() {
    }

    public static Singleton getUniqueInstance() {
       //先判断对象是否已经实例过,没有实例化过才进入加锁代码
        if (uniqueInstance == null) {
            //类对象加锁
            synchronized (Singleton.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

另外,需要注意 uniqueInstance 采用 volatile 关键字修饰也是很有必要。

uniqueInstance = new Singleton(); 

这段代码其实是分为三步执行:

  1. 为 uniqueInstance 分配内存空间
  2. 初始化 uniqueInstance
  3. 将 uniqueInstance 指向分配的内存地址

但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1->3->2。指令重排在单线程环境下不会出先问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如,线程 T1 执行了 1 和 3,此时 T2 调用 getUniqueInstance() 后发现 uniqueInstance 不为空,因此返回 uniqueInstance,但此时 uniqueInstance 还未被初始化。

使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。

1.3 讲一下 synchronized 关键字的底层原理

1.4 说说 JDK1.6 之后的synchronized 关键字底层做了哪些优化,可以详细介绍一下这些优化吗

JDK1.6 对锁的实现引入了大量的优化,如自旋锁、自适应自旋锁,锁消除、锁粗化,偏向锁、轻量级锁等技术来减少锁操作的开销。

锁主要存在四种状态,依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,他们会随着竞争的激烈而逐渐升级。注意锁可以升级不可降级,这种策略是为了提高获得锁和释放锁的效率。

关于这几种优化的详细信息可以查看笔主的这篇文章:https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/java/Multithread/synchronized.md

高效并发-13.锁优化

1.5. 谈谈 synchronized和ReentrantLock 的区别

 

2. volatile关键字

可见性和防止指令重排序

 

3. ThreadLocal

ThreadLocal内存泄漏原因以及避免方案

 

4. 线程池

4.1. 为什么要用线程池?

4.3. 执行execute()方法和submit()方法的区别是什么呢?

并发-Java 并发进阶常见面试题总结_第1张图片

 

5. Atomic 原子类

 

6. AQS

为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量、事件,等等)提供一个框架。

此类的设计目标是成为依靠单个原子 int 值来表示状态的大多数同步器的一个有用基础。

子类必须定义更改此状态的受保护方法,并定义哪种状态对于此对象意味着被获取或被释放。

假定这些条件之后,此类中的其他方法就可以实现所有排队和阻塞机制。子类可以维护其他状态字段,但只是为了获得同步而只追踪使用 getState()setState(int)compareAndSetState(int, int) 方法来操作以原子方式更新的 int 值。

使用

为了将此类用作同步器的基础,需要适当地重新定义以下方法,这是通过使用 getState()setState(int) 和/或 compareAndSetState(int, int) 方法来检查和/或修改同步状态来实现的:

  • tryAcquire(int)
  • tryRelease(int)
  • tryAcquireShared(int)
  • tryReleaseShared(int)
  • isHeldExclusively()

14.条件队列和AQS

 

你可能感兴趣的:(《JavaGuide》)