Java并发编程之常见面试题(二)

21.synchronized使用有哪些注意点?

  • 锁对象不能为空,因为锁是保存在对象头中,对象都没有,就没有对象头
  • 作用域不能过大,把所有代码都被修饰,就是串行了,会影响到程序执行的速度
  • 避免死锁,两个锁,两个线程,线程一持有锁一请求锁二,线程二持有锁二请求锁一

22.如何选择Lock和synchronized关键字?

  • 如何可以的话,不使用这两个,尽量使用JUC包中的类
  • 优先使用synchronized,可以少写代码
  • 特别需要Lock的特性的时候才使用Lock,比如:灵活加锁释放锁机制

23.多线程访问同步方法的各种具体情况

  1. 两个线程同时访问一个对象的同步方法:会发生同步,锁对象都为同一个实例对象;
  2. 两个线程同时访问两个对象的同步方法:互不影响,锁对象不同;
  3. 两个线程访问的是synchronized的静态方法:会发生同步,锁对象都为Class对象,Class对象只有一个;
  4. 同时访问同步方法和非同步方法:非同步方法不受影响,不发生同步;
  5. 访问同一个对象不同的普通同步方法:会发生同步,锁对象默认为同一个实例对象;
  6. 同时访问静态synchronized和非静态synchronized方法:互不影响,静态syn方法的锁对象为Class对象,非静态syn方法的锁对象为一个实例对象this,实例对象和Class对象不是同一个对象,实例对象在堆中,Class对象在方法区中;
  7. 方法抛出异常后,会释放锁

24.多个线程等待同一个sync锁的时候,JVM如何选择获取锁的下一个线程?用的什么算法呢?

处于不公平的状态,和JVM的版本和具体实现都有关系,判定是随机的。

25.sync使得同时只有一个线程执行代码,性能较差,有什么办法可以提升性能?

  • 优化使用范围,要被保护的区域,满足业务需求的情况下,尽可能的小
  • 使用其它类型的Lock,比如读写锁,读不用线程安全,写的时候保证线程安全

26.我想灵活的控制锁的获取和释放,而现在释放锁的时机都被规定死了,怎么办?

自己实现Lock的接口

27.一句话总结synchronized?

JVM通过使用monitor,加减monitor计数器来加锁和解锁,保证了同时只有一个线程可以执行指定代码,从而保证了线程安全,同时具有可重入和不可中断的性质。

28.什么是锁的升级和降级?什么是JVM里的轻量级锁,重量级锁,偏斜锁?

JVM利用关键字使用的次数,来对锁进行优化,升级和降级:把轻量级锁升级到重量级锁等等

29.单例模式的作用及使用场景?

作用:

  1. 节省内存和计算:如果构造函数中有许多资源需要初始化,每次new都需要初始化,十分耗时,单例只需初始化一次;
  2. 保证结果正确:多线程进行统计操作时,需要一个全局的计数器,单例模式可保证计数器只有一个;
  3. 方便管理:一些常见的工具类可以用单例模式管理

使用场景:

  1. 工具类:比如日志工具类,格式转换工具类等,不管在哪里使用,都是无状态的,只需要一个实例对象即可;
  2. 全局信息类:比如全局的计数器,统计网站的全局访问次数;

30.单例模式的各种写法?

/**
 * 饿汉式
 */
public class HungerSingleton {

    private static final HungerSingleton instance = new HungerSingleton();

    private HungerSingleton() {}

    public static HungerSingleton getInstance() {
        return instance;
    }
}
/**
 * 懒汉式,双重检查锁,防止反射
 */
public class DoubleCheckSingleton {

    private static volatile DoubleCheckSingleton instance;

    private DoubleCheckSingleton() {
        if (instance != null) {
            throw new RuntimeException("不允许重复创建实例");
        }
    }

    public DoubleCheckSingleton getInstance() {
        if (instance == null) {
            synchronized (DoubleCheckSingleton.class) {
                if (instance == null) {
                    instance = new DoubleCheckSingleton();
                }
            }
        }
        return instance;
    }
}

/**
 * 饿汉式,静态内部类,防止反射
 */
public class StaticInnerClassSingleton {

    private StaticInnerClassSingleton() {
        if (StaticInnerClass.instance != null) {
            throw new RuntimeException("不允许重复创建实例");
        }
    }

    public StaticInnerClassSingleton getInstance() {
        return StaticInnerClass.instance;
    }

    private static final class StaticInnerClass {
        private static final StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
    }
}

31.哪种单例模式最好?

枚举最好,写法简单,延迟加载,线程安全,防止反射和序列化

32.饿汉式、懒汉式各有什么缺点?

饿汉式:一开始就加载,浪费内存,同时如果需要配置文件配置话,没法去动态调整加载的内容;
懒汉式:写法复杂,线程不安全;

33.为什么用双重检查锁?

线程安全,延迟加载,volatile关键字可保证创建对象的时候能禁止重排序

34.什么是Java内存模型?

  • 起因:不同CPU性能不同,不用JMM的话,需要我们手动同步;
  • 定义:一组规范,规范CPU和代码之间一系列的转换关系;
  • 重排序;
  • 可见性:主内存和本地内存,happens-before原则,volatile:禁止重排序,可见性,近朱者赤,轻量级的synchronized,适用于赋值操作,没有判断和累加操作;
  • 原子性:synchronized:加锁和释放锁原理,近朱者赤;原子:基本类型赋值,引用赋值,原子包;

35.什么是原子操作,Java中有哪些原子操作,生成对象的过程是不是原子操作?

  • 一系列的操作,要么成功,要么都失败;
  • 基本类型和引用赋值,原子包;
  • 生成对象:创建空对象,调用构造方法,引用赋值,不是原子操作;

36.什么是内存可见性?

在这里插入图片描述

37.64位的double和long写入的时候是原子的吗?

32位JVM上有可能出现前32和后32错位的情况,64位JVM是原子的,商用JVM不需要。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章