一文彻底搞懂JUC常见面试题

文章目录

  • 1. JUC简介
  • 2. 进程和线程的区别?
  • 3. 多线程和多进程的区别?
  • 4. 说一下并发编程中的3个概念?(原子、可见、有序)
  • 5. Java的内存模型以及如何保证三种特性?
  • 6. 说一下volatile关键字?
  • 7. 说一下Synchronized关键字?
  • 8. Java中确保线程安全的方法?(Synchronized和Lock、thradlocal和同步,悲观锁和乐观锁CAS)
  • 9. 什么是自旋锁?
  • 10. 线程的5种状态?
  • 11. 什么是守护线程?
  • 12. Java实现多线程的方式(有程序/两种实现的区别)?
  • 13. 进程间的通信?
  • 14. 线程间通信方式(wait和notify)?
  • 15. 说一下线程池?
  • 16. sleep和wait异同?

1. JUC简介

JUC(Java Util Concurrent)是Java工具包中提供的并发编程工具集,它位于java.util.concurrent包下,主要用于简化多线程编程、提高程序性能和可维护性。JUC提供了一系列线程安全的数据结构、并发工具类和线程池等。

JUC中一些常用的并发工具和类:

  • 并发集合类(Concurrent Collections): JUC提供了一系列线程安全的集合类,如ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet等,用于替代传统的非线程安全集合类,可以安全地在多线程环境中使用。

  • 原子变量类(Atomic Variables): JUC提供了一系列原子操作类,如AtomicInteger、AtomicLong、AtomicReference等,用于在多线程环境中执行原子操作,避免了使用锁的开销,提高了程序的性能。

  • 同步工具类(Synchronization Utilities): JUC提供了一些同步工具类,如CountDownLatch、CyclicBarrier、Semaphore等,用于在多线程之间进行协调和同步,实现线程间的等待、通知和同步操作。

  • 线程池(Executor Framework): JUC提供了一套灵活强大的线程池框架,包括Executor、ExecutorService、ThreadPoolExecutor等,用于管理和调度线程的执行,提高了程序的性能和资源利用率。

  • 并发工具类(Concurrent Utilities): JUC还提供了一些其他的并发工具类,如Lock、ReadWriteLock、Phaser、CompletableFuture等,用于实现更复杂的并发模式和解决特定的并发问题。

2. 进程和线程的区别?

进程是程序的一次执行过程,拥有独立的地址空间和资源,是操作系统进行资源分配和调度的基本单位;而线程是进程中的一个执行单元,共享进程的地址空间和资源,是操作系统进行调度的基本单位,多个线程共享同一进程的内存空间和资源。

3. 多线程和多进程的区别?

多线程是在同一进程内部并发执行多个线程,共享同一进程的地址空间和资源,而多进程是在不同进程之间并发执行多个进程,各自拥有独立的地址空间和资源。

4. 说一下并发编程中的3个概念?(原子、可见、有序)

在并发编程中,有三个重要的概念:原子性(Atomicity)、可见性(Visibility)、有序性(Ordering)。

原子性(Atomicity)
原子性是指操作不可被中断的特性,即要么全部执行成功,要么全部不执行,不存在部分执行的情况。在并发编程中,原子操作是一系列操作,要么全部执行成功,要么全部失败,不会被其他线程中断或干扰。

可见性(Visibility)
可见性是指一个线程对共享变量的修改能够被其他线程立即感知到的特性。在并发编程中,如果一个线程修改了共享变量的值,其他线程应该能够立即看到这个变化,而不是在很长一段时间内仍然保持旧值。

有序性(Ordering)
有序性是指程序执行的顺序与代码中的顺序一致的特性。在单线程环境下,程序按照代码中的顺序依次执行;但在并发编程中,由于指令重排等原因,可能会导致程序执行顺序与代码中的顺序不一致。在并发编程中,有序性需要通过同步机制来保证,例如使用锁、volatile关键字、原子操作等。

5. Java的内存模型以及如何保证三种特性?

Java的内存模型(Java Memory Model,JMM)定义了Java程序中线程之间如何访问共享内存的规范,保证了线程安全性、原子性、可见性和有序性等特性。

线程安全性(Thread Safety)
Java内存模型通过各种同步机制(如synchronized关键字、Lock接口、volatile关键字、原子类等)来保证线程安全性。
synchronized关键字可以对代码块或方法进行加锁,确保同一时间只有一个线程可以执行被锁定的代码,从而避免了多线程并发访问共享资源时的竞态条件。
volatile关键字用于声明变量,保证了变量的可见性和有序性,但不保证原子性。
原子类(如AtomicInteger、AtomicLong等)提供了一系列的原子操作,确保了对共享变量的操作是原子的,不会被中断。

原子性(Atomicity)
Java内存模型通过原子类、synchronized关键字等机制来保证对共享变量的操作是原子的。
原子类(Atomic类)提供了一系列的原子操作,如compareAndSet、incrementAndGet、decrementAndGet等,确保了对共享变量的操作是不可分割的,要么全部成功,要么全部失败。

可见性(Visibility)
Java内存模型通过volatile关键字来保证共享变量的可见性。
当一个变量被volatile修饰时,对这个变量的写操作会立即被其他线程所看到,而不会出现缓存一致性的问题,保证了共享变量的修改对其他线程的立即可见性。

有序性(Ordering)
Java内存模型通过volatile关键字和synchronized关键字来保证有序性。
volatile关键字保证了对volatile变量的读写操作都是按照程序中的顺序进行的,不会出现重排序的情况。
synchronized关键字不仅保证了临界区内代码的有序执行,还通过内存屏障(Memory Barrier)来保证了临界区前后的内存操作不会被重排序。

6. 说一下volatile关键字?

volatile是Java中的一个关键字,用于修饰变量,其主要作用是保证变量的可见性和禁止指令重排序,但并不保证原子性。 因此,在多线程环境下,volatile适用于某个变量的写操作不依赖于当前值的情况,而且变量的写操作不会与其他变量的操作存在依赖关系。

可见性(Visibility)
当一个变量被volatile修饰时,对这个变量的修改会立即被其他线程所看到,而不会出现缓存一致性的问题。这是因为volatile变量的写操作会立即被刷新到主内存中,并且对volatile变量的读操作都是直接从主内存中读取的,而不是从线程的工作内存中读取。

禁止指令重排序(Prevent Instruction Reordering)
volatile关键字还可以防止指令重排序,即被volatile修饰的变量在读写操作时会被插入内存屏障(Memory Barrier),防止编译器和处理器对其进行重排序优化。这样可以保证变量的修改顺序和代码中的顺序一致,避免了可能导致数据不一致的重排序情况。

不保证原子性(No Atomicity)
尽管volatile可以保证变量的可见性和禁止指令重排序,但它并不保证对变量的操作是原子的。如果一个变量的操作需要保证原子性,例如自增或自减操作,需要使用synchronized关键字或java.util.concurrent.atomic包下的原子类来保证。

7. 说一下Synchronized关键字?

synchronized关键字是Java中实现同步锁机制的一种方式,通过对共享资源的加锁和释放锁来保证了线程安全,避免了多线程并发访问时可能出现的竞态条件和数据不一致问题。

实现原理:
synchronized关键字可以用来修饰方法或代码块,在多线程环

你可能感兴趣的:(JUC,juc,java,算法,数据结构)