
这里从多线程的角度来进行切入!
首先在我的技术派项目当中,首页采用的多线程来并行加载不同的模块,这里强调的是多个线程并行的执行!那你有没有思考过如果多线程之间交替执行会怎么样呢?顺带的引出了下面的内容。
需要回答的一个问题,线程之间要进行切换,那你了解线程的上下文切换吗?说说机制
既然你提到了线程之间的切换,那他们之间会不会有通信呢?请你了解都有哪些通信的方式?
接着是进一步的深入不同的通信机制之间的差别,主要集中在不同的关键字的使用上了
你平时有用过多线程吗?你在代码中是哪些场景用呢?
用得比较多,比如说在技术派的首页内容加载中,就用到了多线程来并行加载不同的模块,提高页面的响应速度。
那你既然聊到了多线程,那你++了不了解多线程相互之间是怎么进行切换的呢?线程上下文切换了解吗++?
线程的上下文切换是指CPU从一个线程切换到另外一个线程的过程。
在线程切换的过程中,需要保存当前线程的状态,加载下一个线程的上下文!
之所以要这样,是因为 CPU 在同一时刻只能执行一个线程,为了实现多线程并发执行,需要不断地在多个线程之间切换。【这应该要强调是单核CPU】
为了让用户感觉多个线程是在同时执行 的, CPU 资源的分配采用了时间片轮转的方式,线程在时间片内占用 CPU 执行任务。当线程使用完时间片后,就会让出 CPU 让其他线程占用。
那你既然提到了线程之间的上下文切换,那你++了解守护线程吗++?
Java 中的线程分为两类,一种是守护线程,另外一种是用户线程。
JVM 启动时会调用 main 方法,main 方法所在的线程就是一个用户线程。
守护线程是一种专门为其他线程来服务的线程,当主线程结束的时候,无论守护线程的任务是否执行完都会结束。像垃圾回收线程就是一种守护线程,当主线程执行完,那么垃圾回收线程也会结束
只要有一个用户线程还没结束,正常情况下 JVM 就不会退出。
那既然你知道了线程之间是会相互沟通的,如果++不沟通,都是你干你的,我干我的,肯定没有保证线程的安全性++ ,那么请你讲讲,你都知道++线程之间有哪些通信的方式++?
这个部分没有第一时间想到哪些通信的方式,需要补一下:
首先肯定就是volatile和synchronized这两个关键字!
wait-notify生产者-消费者模式,exchanger数据的交换【补】,condition应该是针对的是可以创建多个小房间的那个锁!
线程之间传递信息的方式有多种,比如说使用 volatile 和 synchronized 关键字共享对象、使用 wait() 和 notify() 方法实现生产者-消费者模式、使用 Exchanger 进行数据交换、使用 Condition 实现线程间的协调等。
那你都知道这么多种通信的方式了,那么请你先来讲讲 ++volatile 和 synchronized 关键字共享对象 的通信方式++
volatile保证的变量的可见性,可以用来修饰成员变量,告知程序任何对该变量的访问均需要从共享内存中获取 ,并同步刷新回共享内存,保证所有线程对变量访问的可见性。
synchronized 可以修饰方法,或者同步代码块,确保多个线程在同一个时刻只有一个线程在执行方法或代码块。
多个线程可以通过 volatile 和 synchronized 关键字访问和修改同一个对象,从而实现信息的传递。

emmmmm,你再讲讲++wait-notify生产者-消费者模式的通信方式++?
wait()会让当前正在执行的线程释放锁,并进入等待池当中进行等待,直到被其他线程唤醒
notify()主要的作用就是唤醒等待池当中的线程,如果没有在括号里面进行声明,那么就是随机唤醒等待池当中的某一个线程;如果声明指定了,那就指定唤醒对应的线程
额外讲一讲notifyall(),这个是唤醒全部的线程!
++condition你了解吗?具体会和哪个锁一起发挥作用呢++?
condition的话通常与锁 ReentrantLock 一起使用,为线程提供了一种等待某个条件成真的机制,并允许其他线程在该条件变化时通知等待线程。
相当于是提供了很多个小房间,如果条件成立,就可以进入到对应的房间中!
类比一下前面的wait()方法,Condition 也提供了类似的方法,await() 负责阻塞、signal() 和 signalAll() 负责通知。但是和wait()不同的是,condition可以根据条件来分配不同的锁,让不同的线程根据条件进入到不同的房间当中!

++exchange的通信方式你了解吗?++
补充:对于exchange的方式已经遗忘,需要补充!
Exchanger 是一个同步点,可以在两个线程之间交换数据 。一个线程调用 exchange() 方法,将数据传递给另一个线程,同时接收另一个线程的数据。
++CompletableFuture 的使用方式了解吗?++
CompletableFuture 是 Java 8 引入的一个类,支持异步编程,允许线程在完成计算后将结果传递给其他线程。
聊了那么多,请++你说说如何保证线程的安全性++?
线程安全是指在并发环境下,多个线程访问共享资源时,程序能够正确地执行,而不会出现数据不一致的问题。
为了保证线程安全,可以使用 synchronized 关键字对方法加锁,对代码块加锁。线程在执行同步方法、同步代码块时,会获取类锁或者对象锁,其他线程就会阻塞并等待锁。
如果需要更细粒度的锁,可以使用 ReentrantLock 并发重入锁等。
如果需要保证变量的内存可见性,可以使用 volatile 关键字。
对于简单的原子变量操作,还可以使用 Atomic 原子类。
对于线程独立的数据,可以使用 ThreadLocal 来为每个线程提供专属的变量副本。
对于需要并发容器的地方,可以使用 ConcurrentHashMap、CopyOnWriteArrayList 等。
说一个线程安全的使用场景?
单例模式。在多线程环境下,如果多个线程同时尝试创建实例,单例类必须确保只创建一个实例,并提供一个全局访问点。
饿汉式是一种比较直接的实现方式,它通过在类加载时就立即初始化单例对象来保证线程安全。
class Singleton { private static final Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }
懒汉式单例则在第一次使用时初始化单例对象,这种方式需要使用双重检查锁定来确保线程安全,volatile 关键字用来保证可见性,syncronized 关键字用来保证同步。
class LazySingleton { private static volatile LazySingleton instance; private LazySingleton() {} public static LazySingleton getInstance() { if (instance == null) { // 第一次检查 synchronized (LazySingleton.class) { if (instance == null) { // 第二次检查 instance = new LazySingleton(); } } } return instance; } }
能说一下 Hashtable 的底层数据结构吗?
注意一下,面试过程中一定要听清楚面试官问的是什么!!!
与 HashMap 类似,Hashtable 的底层数据结构也是一个数组加上链表的方式,然后通过 synchronized 加锁来保证线程安全。