Java 并发编程面经

1 synchronized 关键字

  1. 使用 synchronized 关键字修饰的方法为同步方法,由于 java 的每个对象都有一个内置锁,当此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。( synchronized 关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类)
  2. 有 synchronized 关键字修饰的语句块被称为同步代码块,被该关键字修饰的语句块会自动被加上内置锁,从而实现同步。

2 什么是可重入锁?

可重入锁表示锁具有可重入性,例如 synchronized,ReentrantLock 都是可重入锁。可重入性表明了锁的分配机制:基于线程的分配,而不是基于方法调用的分配。举个简单的例子,当一个线程执行到某个 synchronized 方法时,比如说 method1,而在 method1 中会调用另外一个 synchronized 方法 method2,此时线程不必重新去申请锁,而是可以直接执行方法 method2。

class MyClass {
    public synchronized void method1() {
        method2();
    }
     
    public synchronized void method2() {
         
    }
}

method1 和 method2 都用 synchronized 修饰了,假如某一时刻,线程A执行到了 method1,此时线程A获取了这个对象的锁,而由于 method2 也是 synchronized 方法,假如 synchronized 不具备可重入性,此时线程A需要重新申请锁。但是这就会造成一个问题,因为线程A已经持有了该对象的锁,而又在申请获取该对象的锁,这样就会线程A一直等待永远不会获取到的锁。

而由于 synchronized 和 Lock 都具备可重入性,所以不会发生上述现象。

3 什么是可中断锁?

可中断锁即可以相应中断的锁。Lock 是可中断锁,而 synchronized 不是可中断锁。如果某一线程A正在执行锁中的代码,另一线程B正在等待获取该锁,可能由于等待时间过长,线程B不想等待了,想先处理其他事情,我们可以让它中断自己或者在别的线程中中断它,这种就是可中断锁。

4 什么是公平锁?

公平锁即尽量以请求锁的顺序来获取锁。比如同时有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该锁,这种就是公平锁。非公平锁无法保证锁的获取是否按照请求锁的顺序进行的,这样就可能导致某个或者一些线程永远获取不到锁。

synchronized 是非公平锁,它无法保证等待的线程获取锁的顺序。至于 ReentrantLock 和 ReentrantReadWriteLock,它默认情况下是非公平锁,但是可以设置为公平锁。

5 synchronized 什么情况下会释放锁?

  1. 获取锁的线程执行完了该代码块,然后线程释放对锁的占有;
  2. 线程执行发生异常,此时 JVM 会让线程自动释放锁。
  3. 调用 wait 方法,在等待的时候立即释放锁,方便其他的线程使用锁.

6 Lock 和 synchronized 的区别?

  1. Lock 是一个接口,而 synchronized 是 Java 中的关键字,synchronized 是内置的语言实现
  2. synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而 Lock 在发生异常时,如果没有主动通过 unLock() 去释放锁,则很可能造成死锁现象,因此使用 Lock 时需要在 finally 块中释放锁
  3. Lock 可以让等待锁的线程响应中断,而 synchronized 却不行,使用 synchronized 时,等待的线程会一直等待下去,不能够响应中断
  4. 通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到
  5. Lock 可以提高多个线程进行读操作的效率。在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时 Lock 的性能要远远优于 synchronized。所以说,在具体使用时要根据适当情况选择
  6. Lock 可以设置等待锁的时间,而 synchronized 不行

7 什么是 CAS?

CAS(Compare And Swap) 无锁算法: CAS 是乐观锁技术,当多个线程尝试使用 CAS 同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS 有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

8 线程池的作用有哪些?

线程池的作用: 在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。线程池的作用如下:

  1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  2. 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  3. 提高线程的可管理性。

9 什么是线程安全以及解决机制?

线程安全是指在多线程环境中能永远保证程序的正确性,其实,只有存在共享数据时才需要考虑线程安全问题。当一个类被多个线程进行访问并且正确运行,它就是线程安全的。

如何解决?

  • 加锁:

a 锁能使其保护的代码以串行的形式来访问,当给一个复合操作加锁后,能使其成为原子操作。一种错误的思想是只要对写数据的方法加锁,其实这是错的,对数据进行操作的所有方法都需加锁,不管是读还是写

b 加锁时需要考虑性能问题,不能总是一味地给整个方法加锁 synchronized 就了事了,应该将方法中不影响共享状态且执行时间比较长的代码分离出去

c 加锁的含义不仅仅局限于互斥,还包括可见性。为了确保所有线程都能看见最新值,读操作和写操作必须使用同样的锁对象

  • 不共享状态:

无状态对象: 无状态对象(没有字段和引用)一定是线程安全的,因为不会影响到其他线程

线程关闭: 仅在单线程环境下使用

  • 不可变对象:

可以使用 final 修饰的对象保证线程安全,由于 final 修饰的引用型变量(除 String 外)不可变是指引用不可变,但其指向的对象是可变的,所以此类必须安全发布,也即不能对外提供可以修改 final 对象的接口

10 死锁

参考:什么是死锁?死锁的预防?

11 关键字 volatile

关于 Java 关键字 volatile 的总结

12 synchronized 的实现原理

剖析 synchronized 的实现原理

13 JVM 对 synchronized 的优化

JVM 对 synchronized 的优化

14 Synchronized 与 Volatile 之间的区别

  1. Volatile 仅能使用在变量级别; Synchronized 则可以使用在变量、方法和同步代码块级别上。
  2. Volatile 仅能实现变量的修改可见性和有序性,并不能保证原子性;Synchronized 则可以保证变量的可见性、有序性、原子性。
  3. Volatile 不会造成线程的阻塞;Synchronized 可能会造成线程的阻塞。
  4. Volatile 标记的变量不会被编译器优化; Synchronized 标记的变量可以被编译器优化。

15 什么是 Java 内存模型?

别再问什么是Java内存模型了,看这里!

16 Java 并发包都有哪些?

Java多线程进阶(一)—— J.U.C并发包概述

参考:解释一下锁的一些基本概念:可重入锁、可中断锁、公平锁、读写锁
synchronized和ReentrantLock有什么区别
Java并发 - 什么是线程安全(一).

发布了123 篇原创文章 · 获赞 226 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章