0
点赞
收藏
分享

微信扫一扫

java面试--并发篇

以前干嘛去了 2022-03-17 阅读 74

引言

面试题是结合B站楼兰老师的面试课总结而来,可直接看楼兰老师视频 楼兰老师面试课程

java如何开启线程?怎么保证线程安全?

  1. 线程和进程的区别:进程是操作系统进行资源分配的最小单元、线程是操作系统进行任务分配的最小单元,线程属于进程
  2. 如何开启线程:常用的两种方式 继承Thread类,重写run方法、实现Runnable接口,实现run方法,两种实现方法是由于java的单继承多实现的机制,避免继承了Thread就不能继承其他的类,没有扩展性,所以常用的实现Runnable;另外还有一种方法是 实现Callable接口,实现call方法,这个方式是由返回值,如果需要放回线程中的数据时,可以使用此种方法,通过FutureTask创建一个线程,获取到线程返回值;最后就是通过线程池来创建线程(线程池后面单独介绍)。
  3. 如何保证线程安全?
    核心思想就是 加锁 :JVM提供的锁,也就是Synchronized关键字、还有就是JDK提供各种锁Lock

Volatile和Synchronized有什么区别?Volatile能不能保证线程安全?DCL(Double Check Lock)单例为什么要加Volatile?

  1. Volatile和Synchronized有什么区别
    volatile的使用可查看 java并发篇之volatile关键字
    Synchronized关键字,用来加锁。Volatile只是保证变量的线程可见性。通常适用于一个变量在一个线程写,多个线程读的场景。
  2. Volatile能不能保证线程安全?
    不能,Volatile关键字只能保存线程可见性,不能保证原子性
  3. DCL(Double Check Lock)单例为什么要加Volatile?
    首先看以下代码
public class SingDemo {

    private static SingDemo singDemo = new SingDemo();
    // 私有化
    private SingDemo(){};

    public static SingDemo getInstance(){
        return singDemo;
    }

}

这是一个简单的单例模式,在项目启动时就将对象实例化,但是有时想要在用的时候在加载对象,可以将代码改成

public class SingDemo {

    private static SingDemo singDemo;
    // 私有化
    private SingDemo(){};

    public static SingDemo getInstance(){
        if(null == singDemo){
            singDemo = new SingDemo();
        }
        return singDemo;
    }

}

初始化时不new对象,而是在用的时候判断后初始化对象,但是这样的代码就会有线程不安全的问题,同时两个线程访问时,可能会创建两次,这个时候可以加锁

public class SingDemo {

    private static SingDemo singDemo;
    // 私有化
    private SingDemo(){};

    public static SingDemo getInstance(){
        if(null == singDemo){
            synchronized (SingDemo.class){
                if(null == singDemo){
                    singDemo = new SingDemo();
                }
            }
        }
        return singDemo;
    }
}

当线程1进来判断为空,继续进入实例化,这时不管来多少线程都会被锁住,当线程1创建成功之后,后续线程解锁后会再次进行一次判断,这样就不会重复创建了,这种就叫做DCL(Double Check Lock)双重检查。
回归正题,Volatile在DCL中防止高并发的情况下防止指令重排造成的指令重排。
如下图,创建一个 Integer i = 8 这样一个包装类,CPU在底层会分为3步执行,
1、在堆内存中分配控件,不进行初始化
2、对象初始化,设值为8
3、栈建立指针与堆内存的关系
在单线程中不会存在问题,如果在多线程高并发的情况下,可能会出现顺序错误,就叫指令重排,这是就需要Volatile,保证指令的正确顺序
在这里插入图片描述

java线程锁机制是怎样的?偏向锁、轻量级锁、重量级锁有什么区别?

public class JolDemo {
    public static void main(String[] args) {
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        synchronized (o){
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
}

上面代码可以将未加锁和加锁之后的对象在JVM内存对象中的布局给打印出来
在这里插入图片描述
java 的锁只是在对象的Markword中记录一个锁状态,无锁、偏向锁、轻量级锁、重量级锁对应不同的锁状态
在这里插入图片描述
未完待续。。。

举报

相关推荐

0 条评论