收下这一波2021年,最新的,Java并发面试题(中)

简介: 收下这一波2021年,最新的,Java并发面试题

29. Java中的wait()和sleep()方法之间有什么区别?

等待():

  • wait()方法释放锁定。
  • wait()是Object类的方法。
  • wait()是非静态方法–公共最终void wait()引发InterruptedException {//…}
  • 应该通过notify()或notifyAll()方法通知wait()。
  • 需要从循环中调用wait()方法以处理错误警报。
  • 必须从同步上下文(即同步方法或块)中调用wait()方法,否则它将引发IllegalMonitorStateException

sleep():

  • sleep()方法不会释放锁。
  • sleep()是java.lang.Thread类的方法。
  • sleep()是静态方法–公共静态无效睡眠(长毫秒,int nanos)抛出InterruptedException {//…}
  • 在指定的时间后,sleep()完成。
  • sleep()最好不要从循环中调用(即参见下面的代码)。
  • sleep()可以从任何地方调用。没有具体要求。

30.当未捕获的异常离开run()方法时会发生什么

我可能碰巧一个未经检查的异常从run()方法中逃逸了在这种情况下,线程由Java虚拟机停止。通过将实现接口的实例注册UncaughtExceptionHandler为异常处理程序,可以捕获此异常

这可以通过调用static方法来完成,该方法Thread.setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler)告诉JVM在线程自身上没有注册任何特定的处理程序的情况下使用提供的处理程序,或者通过setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler)在线程实例本身上进行调用

31.两个接口Runnable

Callable?

接口Runnable定义了run()没有任何返回值Callable的方法call()而接口则允许方法返回值并抛出异常。

32.什么是关机钩?

关闭钩子是在JVM关闭时执行的线程。可以通过addShutdownHook(Runnable)在Runtime实例上调用来注册它

Runtime.getRuntime().addShutdownHook(new Thread() {
    @Override
    public void run() {
    }
});

2.2通过sleep暂停执行

33.如何防止繁忙的等待?

防止繁忙等待的一种方法是使当前线程在给定的时间内休眠。这可以java.lang.Thread.sleep(long)通过传递方法将进入睡眠的毫秒数作为参数来调用该方法来完成

34.我们可以Thread.sleep()用于实时处理吗?

传递给的毫秒数Thread.sleep(long)仅表示调度程序不需要当前线程执行多长时间。根据实际的实现,调度程序可能会让线程提前或延迟几毫秒再执行一次。因此,Thread.sleep()不应将的调用用于实时处理。

35.该方法Thread.yield()做什么?

静态方法的调用为Thread.yield()调度程序提供了一个提示,即当前线程愿意释放处理器。调度程序可以随意忽略此提示。由于未定义调用哪个线程将获得处理器Thread.yield(),因此甚至有可能当前线程成为要执行的“下一个”线程。

36.该类有哪些用例java.util.concurrent.Future

该类的实例java.util.concurrent.Future用于表示异步计算的结果,这些结果无法立即获得。因此,该类提供了一些方法来检查异步计算是否已完成,取消任务并检索实际结果。后者可以通过提供的两种get()方法来完成第一个get()方法不带参数,并阻塞直到结果可用为止;第二个get()方法带一个超时参数,如果结果在给定的时间范围内不可用,则该超时参数使方法调用返回。

37.我们如何在Java中停止线程?

要停止线程,可以使用指向当前线程的易失性引用,该引用可以被其他线程设置为null,以指示当前线程应停止其执行:

private static class MyStopThread extends Thread {
    private volatile Thread stopIndicator;
    public void start() {
        stopIndicator = new Thread(this);
        stopIndicator.start();
    }
    public void stopThread() {
        stopIndicator = null;
    }
    @Override
    public void run() {
        Thread thisThread = Thread.currentThread();
        while(thisThread == stopIndicator) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }
    }
}

2.3中断

38.如何唤醒使用前已进入睡眠状态的线程Thread.sleep()

该方法interrupt()java.lang.Thread中断睡眠线程。已通过调用进入睡眠状态的中断线程Thread.sleep()被唤醒InterruptedException

public class InterruptExample implements Runnable {
    public void run() {
        try {
            Thread.sleep(Long.MAX_VALUE);
        } catch (InterruptedException e) {
            System.out.println("["+Thread.currentThread().getName()+"] Interrupted by exception!");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread myThread = new Thread(new InterruptExample(), "myThread");
        myThread.start();
        System.out.println("["+Thread.currentThread().getName()+"] Sleeping in main thread for 5s...");
        Thread.sleep(5000);
        System.out.println("["+Thread.currentThread().getName()+"] Interrupting myThread");
        myThread.interrupt();
    }
}

39.线程如何查询是否已被中断?

如果线程不在Thread.sleep()抛出的方法之内InterruptedException,则该线程可以通过调用静态方法Thread.interrupted()isInterrupted()从其继承的方法来查询是否已被中断java.lang.Thread.

40.应该如何InterruptedException处理?

sleep()join()抛出这样的方法InterruptedException告诉调用者另一个线程已中断该线程。在大多数情况下,这样做是为了告诉当前线程停止其当前计算并意外完成它们。因此,通过捕获异常并仅将其记录到控制台或某些日志文件中来忽略该异常通常不是处理此类异常的适当方法。此异常的问题在于,run()Runnable接口的方法不允许run()抛出任何异常。因此,仅将其重新添加无济于事。这意味着的实现run()必须自己处理此检查的异常,这通常会导致其被捕获和忽略的事实。


2.4加入

41.在启动子线程之后,我们如何在父线程中等待子线程的终止?

通过调用join()线程的实例变量上的方法等待线程终止

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
    }
});
thread.start();
thread.join();

42.以下程序的输出是什么?

上面的代码的输出为“ false”。尽管MyDaemonThread的实例是守护程序线程,但是的调用join()会使主线程等待,直到守护程序线程的执行完成。因此,调用isAlive()线程实例显示守护程序线程不再运行。

3.同步

43.同步方法和同步块之间的区别?

  • 同步块减小了锁定范围,但是同步方法的锁定范围是整个方法。
  • 同步块的性能更好,因为只有关键部分被锁定,但是同步方法的性能比块差。
  • 同步块提供了对锁的精细控制,但对此对象或类级别锁表示的当前对象提供了同步方法锁。
  • 同步块可以抛出NullPointerException,但同步方法不会抛出。
  • 同步块:同步(此){}
  • 同步方法:公共同步void fun(){}

44.什么是Java中的volatile关键字,它与Java中的同步方法有何不同?

使用volatile强制线程直接从RAM存储器读取和写入变量。因此,当许多线程都使用相同的volatile变量时,它们都将看到RAM内存中存在的最新版本,而不是高速缓存中可能的旧副本。当线程进入同步块时,它需要控制监视变量。所有其他线程等待,直到第一个线程从同步块退出。为了确保所有线程都能看到相同的修改,同步块中使用的所有变量都直接从RAM内存而不是从缓存副本读取和写入。

45.同步关键字用于什么目的?

当您必须实现对资源的互斥访问(例如某些静态值或某些文件引用)时,可以使用同步块包含与互斥资源一起使用的代码:

synchronized (SynchronizedCounter.class) {
    counter++;
}

46.什么是信号量?

信号量是一种数据结构,它维护一组必须由竞争线程获取的许可。因此,信号量可用于控制有多少线程同时访问关键部分或资源。因此,的构造函数java.util.concurrent.Semaphore将线程竞争的许可数量作为第一个参数。每次调用其acquire()方法都会尝试获取可用许可之一。acquire()在下一个允许获得可用之前,没有任何参数块的方法稍后,当线程完成对关键资源的工作时,它可以通过release()在Semaphore实例上调用该方法来释放许可

47.什么是CountDownLatch

SDK类CountDownLatch提供了一个同步辅助工具,可用于实现以下场景:线程必须等待,直到其他一些线程达到相同状态才能启动所有线程。通过提供一个递减的同步计数器,直到其达到零值,即可完成此操作。CountDownLatch实例达到零后,将允许所有线程继续进行。可以使用计数器的值1来让所有线程在给定的时间点启动,也可以等待直到多个线程完成。在后一种情况下,计数器将使用线程数进行初始化,并且每个完成其工作的线程都会将锁存器递减一个。

48. aCountDownLatch和a有CyclicBarrier什么区别

这两个SDK类都在内部维护一个计数器,该计数器由不同的线程递减。线程等待直到内部计数器达到零值,然后从那里继续。但是与CountDownLatch相反,该类CyclicBarrier将值重置为零后将内部值重置为初始值。顾名思义,CyclicBarrier因此的实例可用于实现用例,其中线程必须一次又一次地等待彼此。

3.1内部锁和同步

49.同步方法获得什么内在锁?

同步方法获取该方法对象的固有锁定,并在方法返回时释放该锁定。即使该方法引发异常,也将释放固有锁定。因此,同步方法等于以下代码:

public void method() {
    synchronized(this) {
        ...
    }
}

50.如果两个线程同时在不同的对象实例上调用同步方法,这些线程之一会阻塞吗?

两种方法都锁定同一监视器。因此,您不能同时在不同线程上的同一对象上执行它们(两种方法之一将阻塞,直到另一种方法完成)。

51.构造函数可以同步吗?

否,构造函数无法同步。之所以导致语法错误,是因为只有构造线程才有权访问正在构造的对象。

52. Lock与同步相比有什么好处?

锁的优点是:

  • 有可能使它们公平
  • 在等待Lock对象时,可以使线程响应中断。
  • 可以尝试获取锁,但是如果无法获取锁,则立即返回或在超时后返回
  • 可以在不同的范围内以不同的顺序获取和释放锁

53.原始值可以用于内部锁吗?

不可以,原始值不能用于内部锁。

54.内在锁是否可重入?

是的,同一线程可以一次又一次地访问固有锁。否则,获取锁的代码将必须注意,它不会偶然尝试获取已获取的锁。

55.我们对公平锁有什么了解?

选择是通过障碍的一些独家资源的下一个线程时,一个公平的锁占用线程的等待时间考虑在内。公平锁的示例实现由Java SDK提供:java.util.concurrent.locks.ReentrantLock如果使用布尔标志设置为true的构造函数,则ReentrantLock授予对等待时间最长的线程的访问权限。

56. SDK类ReadWriteLock使用了哪种减少锁争用的技术?

SDK类ReadWriteLock使用以下事实:并发线程在没有其他线程尝试更新值的情况下想要读取值时不必获取锁。这由一对锁实现,一个锁用于只读操作,一个锁用于写操作。尽管可以通过多个线程获得只读锁,但是该实现保证释放写锁后,所有读取操作都将看到更新的值。

3.2原子访问

57.我们通过原子操作了解什么?

原子操作是完全执行或根本不执行的操作。

58.语句c ++是原子的吗?

不,一个整数变量的增量包括一个以上的运算。首先,我们必须加载c的当前值,将其递增,然后最后将新值存储回去。执行此增量的当前线程可能会在这三个步骤中的任何一个之间中断,因此此操作不是原子操作。

59. Java中哪些操作是原子操作?

Java语言提供了一些原子性的基本操作,因此可用于确保并发线程始终看到相同的值:

  • 对参考变量和原始变量(长整型和双精度型除外)的读写操作
  • 对声明为易失性的所有变量的读写操作

4.活泼

4.1死锁

60.我们对僵局有什么了解?

死锁是一种情况,其中两个(或更多)线程各自在另一个线程上等待以释放其已锁定的资源,而线程本身已锁定另一个线程在等待的资源:

  • 线程1:锁定资源A,等待资源B
  • 线程2:锁定资源B,等待资源A

61.僵局情况有哪些要求?

通常,可以确定以下死锁要求:

  • 互斥:有一种资源在任何时间点只能由一个线程访问。
  • 资源持有:锁定一个资源后,线程尝试获取对某个其他排他资源的另一个锁定。
  • 无抢占:没有机制,如果一个线程在特定时间段内持有锁,则该机制可以释放资源。
  • 循环等待:在运行时发生一个星座,其中两个(或更多)线程分别在另一个线程上等待以释放已锁定的资源。

62.完全可以防止死锁吗?

为了防止死锁,必须消除一个或多个死锁的要求:

  • 互斥:在某些情况下,可以通过使用乐观锁定来防止互斥。
  • 资源持有:线程无法成功获取所有排他锁时,可能会释放其所有排他锁。
  • 无抢占:对独占锁使用超时将在给定时间后释放锁。
  • 循环等待:当所有线程以相同顺序获得所有排他锁时,不会发生循环等待。

63.是否可以实现死锁检测?

当监视所有排他锁并将其建模为有向图时,死锁检测系统可以搜索两个线程,每个线程都在等待另一个线程以释放已锁定的资源。然后可以通过某种异常强制等待线程释放另一个线程正在等待的锁。

4.2饥饿和活锁

64.什么是活锁?

活锁是这样的情况,其中两个或更多线程通过响应另一个线程引起的动作而相互阻塞。与死锁情况相反,死锁情况是两个或多个线程在一个特定状态下等待,而参与活动锁的线程则以防止其正常工作进展的方式更改其状态。一个示例是这样一种情况,其中两个线程尝试获取两个锁,但是在无法获取第二个锁时释放它们获取的锁。现在可能会发生,两个线程同时尝试获取第一个线程。由于只有一个线程成功,因此第二线程可以成功获取第二锁。现在,两个线程都持有两个不同的锁,但是由于两个线程都想要拥有两个锁,因此它们释放其锁并从头开始尝试。现在可能一次又一次地发生这种情况。

65.通过线程饥饿我们了解什么?

具有较低优先级的线程比具有较高优先级的线程获得的执行时间更少。当具有较低优先级的线程执行长时间的持久计算时,可能会发生这些线程没有足够的时间及时完成其计算的情况。它们似乎“饿死了”,因为具有更高优先级的线程会占用它们的计算时间。

目录
相关文章
|
1月前
|
安全 架构师 Java
Java大厂面试高频:Collection 和 Collections 到底咋回答?
Java中的`Collection`和`Collections`是两个容易混淆的概念。`Collection`是集合框架的根接口,定义了集合的基本操作方法,如添加、删除等;而`Collections`是一个工具类,提供了操作集合的静态方法,如排序、查找、同步化等。简单来说,`Collection`关注数据结构,`Collections`则提供功能增强。通过小王的面试经历,我们可以更好地理解这两者的区别及其在实际开发中的应用。希望这篇文章能帮助你掌握这个经典面试题。
51 4
|
3月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
140 2
|
1月前
|
Java 程序员
Java社招面试中的高频考点:Callable、Future与FutureTask详解
大家好,我是小米。本文主要讲解Java多线程编程中的三个重要概念:Callable、Future和FutureTask。它们在实际开发中帮助我们更灵活、高效地处理多线程任务,尤其适合社招面试场景。通过 Callable 可以定义有返回值且可能抛出异常的任务;Future 用于获取任务结果并提供取消和检查状态的功能;FutureTask 则结合了两者的优势,既可执行任务又可获取结果。掌握这些知识不仅能提升你的编程能力,还能让你在面试中脱颖而出。文中结合实例详细介绍了这三个概念的使用方法及其区别与联系。希望对大家有所帮助!
183 60
|
13天前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
72 14
|
16天前
|
安全 Java 程序员
Java 面试必问!线程构造方法和静态块的执行线程到底是谁?
大家好,我是小米。今天聊聊Java多线程面试题:线程类的构造方法和静态块是由哪个线程调用的?构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节有助于掌握Java多线程机制。下期再见! 简介: 本文通过一个常见的Java多线程面试题,详细讲解了线程类的构造方法和静态块是由哪个线程调用的。构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节对掌握Java多线程编程至关重要。
48 13
|
1月前
|
算法 安全 Java
Java线程调度揭秘:从算法到策略,让你面试稳赢!
在社招面试中,关于线程调度和同步的相关问题常常让人感到棘手。今天,我们将深入解析Java中的线程调度算法、调度策略,探讨线程调度器、时间分片的工作原理,并带你了解常见的线程同步方法。让我们一起破解这些面试难题,提升你的Java并发编程技能!
84 16
|
1月前
|
Java 程序员 调度
Java 高级面试技巧:yield() 与 sleep() 方法的使用场景和区别
本文详细解析了 Java 中 `Thread` 类的 `yield()` 和 `sleep()` 方法,解释了它们的作用、区别及为什么是静态方法。`yield()` 让当前线程释放 CPU 时间片,给其他同等优先级线程运行机会,但不保证暂停;`sleep()` 则让线程进入休眠状态,指定时间后继续执行。两者都是静态方法,因为它们影响线程调度机制而非单一线程行为。这些知识点在面试中常被提及,掌握它们有助于更好地应对多线程编程问题。
66 9
|
1月前
|
安全 Java 程序员
Java面试必问!run() 和 start() 方法到底有啥区别?
在多线程编程中,run和 start方法常常让开发者感到困惑。为什么调用 start 才能启动线程,而直接调用 run只是普通方法调用?这篇文章将通过一个简单的例子,详细解析这两者的区别,帮助你在面试中脱颖而出,理解多线程背后的机制和原理。
70 12
|
1月前
|
监控 Dubbo Java
Java Dubbo 面试题
Java Dubbo相关基础面试题
|
1月前
|
SQL Java 数据库连接
Java MyBatis 面试题
Java MyBatis相关基础面试题