精选 19 道多线程面试题,有答案边看边学

本文详细介绍了Java多线程面试的19个关键问题,涵盖了线程停止、多线程实现、同步机制、线程安全、锁的种类、最佳实践、性能比较以及线程状态等核心知识点,旨在帮助程序员深入理解Java多线程的运用与优化。
摘要由CSDN通过智能技术生成

一. Java 程序如何停止一个线程?

建议使用”异常法”来终止线程的继续运行。在想要被中断执行的线程中, 调用 interrupted()方法,该方法用来检验当前线程是否已经被中断,即该线程 是否被打上了中断的标记,并不会使得线程立即停止运行,如果返回 true,则 抛出异常,停止线程的运行。在线程外,调用 interrupt()方法,使得该线程打 上中断的标记。

二. 说一下 java 中的多线程。

1. Java 中实现多线程的四种方式(创建多线程的四种方式)?

①. 继承 Thread 类创建线程类

  • 定义 Thread 类的子类,并重写该类的 run 方法,该 run 方法的方 法体就代表了线程要完成的任务。因此把 run()方法称为执行体。

  • 创建 Thread 子类的实例,即创建了线程对象。

  • 调用线程对象的 start()方法来启动该线程。

②. 通过 Runnable 接口创建线程类

  • 定义 Runnable 接口的实现类,并重写该接口的 run()方法,该 run() 方法的方法体同样是该线程的线程执行体。

  • 创建 Runnable 实现类的实例,并依此实例作为 Thread 的 target 来创建 Thread 对象,该 Thread 对象才是真正的线程对象。

  • 调用线程对象的 start()方法来启动该线程。

③. 通过 Callable 和 Future 创建线程

  • 创建 Callable 接口的实现类,并实现 call()方法,该 call()方法将作 为线程执行体,并且有返回值。

  • 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call()方法的返回值。

  • 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线 程。

  • 调用 FutureTask 对象的 get()方法来获得子线程执行结束后的返回值。

④. 通过线程池创建线程

利用线程池不用 new 就可以创建线程,线程可复用,利用 Executors 创 建线程池。

扩展 1:Java 中 Runnable 和 Callable 有什么不同?

  • Callable 定义的方法是 call(),而 Runnable 定义的方法是 run()。

  • Callable 的 call 方法可以有返回值,而 Runnable 的 run 方法不能有 返回值。

  • Callable 的 call 方法可抛出异常,而 Runnable 的 run 方法不能抛出 异常。

扩展 2:一个类是否可以同时继承 Thread 和实现 Runnable 接口?<

可以。比如下面的程序可以通过编译。因为 Test 类从 Thread 类中继承了 run()方法,这个 run()方法可以被当作对 Runnable 接口的实现。

public class Test extends Thread implements Runnable {
 public static void main(String[] args) {
 Thread t = new Thread(new Test());
 t.start();
 }
}

2. 实现多线程的同步。

在多线程的环境中,经常会遇到数据的共享问题,即当多个线程需要访问同 一资源时,他们需要以某种顺序来确保该资源在某一时刻只能被一个线程使用, 否则,程序的运行结果将会是不可预料的,在这种情况下,就必须对数据进行 同步。

在 Java 中,提供了四种方式来实现同步互斥访问: synchronized 和 Lock 和 wait()/notify()/notifyAll()方法和 CAS。

①. synchronized 的用法

A . 同步代码块

synchronized 块写法: 
synchronized(object) 
{
}

表示线程在执行的时候会将 object 对象上锁。(注意这个对象可以是任意 类的对象,也可以使用 this 关键字或者是 class 对象)。

可能一个方法中只有几行代码会涉及到线程同步问题,所以 synchronized 块 比 synchronized 方法更加细粒度地控制了多个线程的访问, 只有 synchronized 块中的内容不能同时被多个线程所访问,方法中的其他语句仍然 可以同时被多个线程所访问(包括 synchronized 块之前的和之后的)。

B . 修饰非静态的方法

当 synchronized 关键字修饰一个方法的时候,该方法叫做同步方法。

Java 中的每个对象都有一个锁(lock),或者叫做监视器(monitor), 当一个线程访问某个对象的 synchronized 方法时,将该对象上锁,其他任何 线程都无法再去访问该对象的 synchronized 方法了(这里是指所有的同步方 法,而不仅仅是同一个方法),直到之前的那个线程执行方法完毕后(或者是 抛出了异常),才将该对象的锁释放掉,其他线程才有可能再去访问该对象的 synchronized 方法。

注意这时候是给对象上锁,如果是不同的对象,则各个对象之间没有限制 关系。

注意,如果一个对象有多个 synchronized 方法,某一时刻某个线程已经进入 到了某个 synchronized 方法,那么在该方法没有执行完毕前,其他线程是无法访 问该对象的任何 synchronized 方法的。

C . 修饰静态的方法

当一个 synchronized 关键字修饰的方法同时又被 static 修饰,之前说过, 非静态的同步方法会将对象上锁,但是静态方法不属于对象,而是属于类,它 会将这个方法所在的类的 Class 对象上锁。一个类不管生成多少个对象,它们 所对应的是同一个 Class 对象。

因此,当线程分别访问同一个类的两个对象的两个 static,synchronized 方法时,它们的执行顺序也是顺序的,也就是说一个线程先去执行方法,执行 完毕后另一个线程才开始。

结论:

  • synchronized 方法是一种粗粒度的并发控制,某一时刻,只能有一个线 程执行该 synchronized 方法。

  • synchronized 块则是一种细粒度的并发控制,只会将块中的代码同步, 位于方法内,synchronized 块之外的其他代码是可以被多个线程同时访问到 的。

②.Lock 的用法

使用 Lock 必须在 try-catch-finally 块中进行,并且将释放锁的操作放在 finally 块中进行,以保证锁一定被释放,防止死锁的发生。通常使用 Lock 来 进行同步的话,是以下面这种形式去使用的:

Lock
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值