返回

Java并发面试常见考点

后端







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

Java中开启线程有两种方式:

* 使用`Thread`类
* 使用`Runnable`接口

使用`Thread`类时,需要继承`Thread`类,然后重写`run()`方法,在`run()`方法中编写线程需要执行的任务。

使用`Runnable`接口时,需要实现`Runnable`接口,然后将实现的类作为参数传递给`Thread`类的构造函数,在`Thread`类的构造函数中会调用`Runnable`接口的`run()`方法,在`run()`方法中编写线程需要执行的任务。

保证线程安全的方法有很多,常见的有:

* 使用`synchronized`
* 使用`lock`和`Condition`
* 使用`volatile`关键字
* 使用线程池

## 线程和进程的区别

线程和进程都是操作系统的执行单元,但两者之间存在着本质的区别:

* 进程是操作系统进行资源分配的最小单元,而线程是进程中的一个执行单元。
* 进程拥有独立的地址空间,而线程共享进程的地址空间。
* 进程可以创建和销毁线程,而线程不能创建和销毁进程。

## Java内存模型

Java内存模型(JMM)规定了Java程序中不同线程之间共享变量的访问规则,确保了Java程序的正确执行。

JMM将内存分为主内存和工作内存,主内存是所有线程共享的内存,工作内存是每个线程私有的内存。线程只能访问自己的工作内存,不能直接访问其他线程的工作内存。

当一个线程需要访问共享变量时,会先从自己的工作内存中读取共享变量的值,如果工作内存中没有共享变量的值,则会从主内存中读取共享变量的值,并将共享变量的值存储到自己的工作内存中。

当一个线程修改共享变量的值时,会先将共享变量的值存储到自己的工作内存中,然后通知其他线程共享变量的值已被修改。其他线程在收到通知后,会从主内存中重新读取共享变量的值。

## volatile

`volatile`关键字可以保证共享变量的可见性,即当一个线程修改了共享变量的值时,其他线程能够立即看到修改后的值。

`volatile`关键字还可以禁止指令重排序,即编译器和处理器不能对带有`volatile`关键字的共享变量的访问进行重排序。

## synchronized

`synchronized`关键字可以保证共享变量的原子性,即当一个线程正在访问共享变量时,其他线程不能访问该共享变量。

`synchronized`关键字还可以保证共享变量的可见性,即当一个线程修改了共享变量的值时,其他线程能够立即看到修改后的值。

## lock和Condition

`lock`和`Condition`是`java.util.concurrent`包中的两个类,可以用来实现线程同步。

`lock`类是一个锁对象,可以用来控制对共享变量的访问。当一个线程需要访问共享变量时,需要先获取`lock`对象上的锁,获取锁成功后,该线程才能访问共享变量。当该线程访问共享变量完毕后,需要释放`lock`对象上的锁,以便其他线程可以访问共享变量。

`Condition`类是一个条件变量,可以用来实现线程之间的等待和通知。当一个线程需要等待某个条件满足时,可以调用`Condition`对象上的`await()`方法,该线程将进入等待状态。当其他线程满足了该条件后,可以调用`Condition`对象上的`signal()`方法,唤醒等待该条件的线程。

## 线程池

线程池是一个管理线程的组件,可以提高线程的利用率,减少创建和销毁线程的开销。

线程池可以分为固定大小线程池、可伸缩线程池和工作窃取线程池。

* 固定大小线程池:线程池中的线程数是固定的,不会随着任务数量的变化而变化。
* 可伸缩线程池:线程池中的线程数可以随着任务数量的变化而变化,当任务数量增加时,线程池会创建新的线程来处理任务,当任务数量减少时,线程池会销毁多余的线程。
* 工作窃取线程池:工作窃取线程池中的线程会主动从其他线程窃取任务来执行,这样可以提高线程的利用率。

## Future、Callable和Executor

`Future`类表示一个异步计算的结果,`Callable`接口表示一个可以异步执行的任务,`Executor`接口表示一个可以执行任务的组件。

当需要执行一个异步任务时,可以创建一个`Callable`接口的实现类,然后将该实现类作为参数传递给`Executor`接口的`submit()`方法,`Executor`接口的`submit()`方法会创建一个线程来执行该任务,并返回一个`Future`对象。

调用`Future`对象的`get()`方法可以获取异步任务的执行结果。

## CompletableFuture

`CompletableFuture`类是`java.util.concurrent`包中的一个类,可以用来实现异步编程。

`CompletableFuture`类提供了许多方法来组合和转换异步任务,例如`thenApply()`方法、`thenAccept()`方法和`thenCombine()`方法。

`CompletableFuture`类还可以用来实现异步回调,例如`whenComplete()`方法和`handle()`方法。

## 结束语

本文详细介绍了Java并发面试常见考点,包括Java如何开启线程、怎么保证线程安全、线程和进程的区别、Java内存模型、volatile、synchronized、lock、Condition、线程池、Future、Callable、Executor和CompletableFuture等。希望能对读者有所帮助。