面试 Java 并发编程八股文十问十答第四期

面试 Java 并发编程八股文十问十答第四期

作者:程序员小白条个人博客

相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!

⭐点赞⭐收藏⭐不迷路!⭐

1)Java 中你怎样唤醒一个阻塞的线程?

要唤醒一个阻塞的线程,通常需要使用wait()notify()notifyAll() 方法配合使用。下面是一般的步骤:

  1. 在同步代码块中调用 wait() 方法使线程进入等待状态。

  2. 当某个条件满足时,调用 notify()notifyAll() 方法唤醒等待的线程。

  3. 被唤醒的线程会重新竞争对象锁,一旦获得锁,就可以继续执行。

    synchronized (monitor) {
    while (condition) {
    monitor.wait(); // 线程进入等待状态
    }

     // 满足条件后唤醒线程
     monitor.notify(); // 或者 monitor.notifyAll();
    

    }

2)notify() 和 notifyAll() 有什么区别?

  • notify() 方法用于唤醒等待队列中的一个线程,具体唤醒哪个线程取决于调度器的选择。
  • notifyAll() 方法用于唤醒等待队列中的所有线程,让它们有机会竞争对象锁。

通常情况下,如果只有一个线程需要被唤醒,可以使用 notify() 方法以减少不必要的竞争。但是,如果有多个线程需要被唤醒,或者不确定有多少线程需要唤醒时,可以使用 notifyAll() 方法确保所有等待的线程都有机会继续执行。

3)如何在两个线程间共享数据?

在 Java 中,两个线程之间共享数据的常见方式包括使用共享对象或者使用线程间通信机制。以下是一些常见的方法:

  1. 共享对象:两个线程可以共享同一个对象,通过对象的成员变量来共享数据。需要确保线程安全,可以使用同步方法或同步块来保护共享数据的访问。
  2. 线程间通信 :可以使用 wait()notify()notifyAll() 等方法来实现线程间的通信。一个线程在等待某个条件满足时调用 wait() 进入等待状态,另一个线程在满足条件时调用 notify()notifyAll() 唤醒等待的线程。
  3. 线程安全的数据结构 :使用线程安全的数据结构,比如 ConcurrentHashMapConcurrentLinkedQueue 等,来实现线程间的数据共享。
  4. 使用锁 :可以使用 ReentrantLocksynchronized 关键字来保护共享数据的访问,确保线程安全。

在实现线程间数据共享时,需要注意线程安全性和避免发生竞态条件,以确保多线程环境下的数据一致性和正确性。

4)Java 如何实现多线程之间的通讯和协作?

在 Java 中,多线程之间的通讯和协作可以通过以下方式实现:

  1. 使用共享对象 :多个线程共享同一个对象,通过对象的成员变量进行通讯。可以使用 wait()notify()notifyAll() 方法实现线程间的等待和唤醒。
  2. 使用线程安全的队列 :可以使用 BlockingQueue 或其他线程安全的数据结构来实现线程之间的数据传递和协作。
  3. 使用信号量Semaphore 类可以用来控制同时访问共享资源的线程数量,实现线程之间的协作。
  4. 使用 CountDownLatch 和 CyclicBarrierCountDownLatchCyclicBarrier 类可以用来实现多个线程之间的协作和同步。
  5. 使用 Lock 和 ConditionReentrantLockCondition 类可以实现更灵活的线程协作机制。

5)同步方法和同步块,哪个是更好的选择?

在选择同步方法和同步块时,取决于具体情况。一般来说:

  • 同步方法:使用同步方法可以简化代码,因为整个方法体都会被同步,不需要显式地编写同步代码块。但是同步方法的粒度比较粗,可能会影响程序的性能。
  • 同步块:使用同步块可以精确地控制需要同步的代码块,避免不必要的同步,提高程序的性能。但是需要显式地编写同步代码块,增加了代码的复杂性。

一般来说,如果需要同步的代码比较少,可以考虑使用同步块;如果整个方法都需要同步,可以考虑使用同步方法。在实际应用中,需要根据具体情况进行权衡和选择。

6)什么是线程同步和线程互斥,有哪几种实现方式?

  • 线程同步:线程同步是指多个线程之间按照一定的顺序执行,保证共享资源的正确访问。线程同步可以避免竞态条件和数据不一致的问题。
  • 线程互斥:线程互斥是指多个线程在访问共享资源时,通过加锁的方式实现互斥访问,即同一时刻只有一个线程可以访问共享资源,其他线程需要等待。

几种实现线程同步和线程互斥的方式包括:

  1. 使用 synchronized 关键字 :可以在方法上或代码块中使用 synchronized 关键字来实现线程同步和互斥。
  2. 使用 Lock 接口ReentrantLock 类提供了与synchronized 关键字类似的功能,可以更灵活地控制锁的获取和释放。
  3. 使用 volatile 关键字volatile 关键字可以保证变量的可见性,但不能保证原子性,适用于简单的标志位等情况。
  4. 使用 wait()、notify() 和 notifyAll():通过这些方法可以实现线程之间的等待和唤醒,实现线程间的协作和互斥。
  5. 使用并发容器 :Java 中的并发容器如 ConcurrentHashMapConcurrentLinkedQueue 等提供了线程安全的数据结构,可以避免手动加锁。

选择合适的线程同步和互斥方式取决于具体的需求和场景,需要根据实际情况进行选择和权衡。

7)在监视器(Monitor)内部,是如何做线程同步的?程序应该做哪种级别的同步?

在 Java 中,监视器(Monitor)是通过对象的内置锁(也称为监视器锁)来实现线程同步的。当一个线程进入一个 synchronized 方法或代码块时,它会尝试获取对象的内置锁,如果锁已经被其他线程持有,则该线程会被阻塞,直到锁被释放。

程序应该根据需要选择合适的同步级别,可以在方法级别或代码块级别进行同步。一般来说,推荐使用更细粒度的同步,即在尽可能小的代码块中加锁,以减少同步的范围,提高程序的性能。

8)如果你提交任务时,线程池队列已满,这时会发生什么?

当线程池队列已满时,如果线程池中的线程数量未达到最大线程数限制,新提交的任务会尝试创建新的线程来执行。如果线程池中的线程数量已经达到最大线程数限制,且队列已满,则根据线程池的拒绝策略来处理新提交的任务。

常见的拒绝策略包括:

  • AbortPolicy:直接抛出 RejectedExecutionException 异常。
  • CallerRunsPolicy:由提交任务的线程来执行这个任务。
  • DiscardPolicy:直接丢弃新任务,不抛出异常。
  • DiscardOldestPolicy:丢弃队列中等待时间最长的任务,然后尝试重新提交新任务。

可以根据具体的业务需求选择合适的拒绝策略,或者自定义拒绝策略来处理任务提交时线程池队列已满的情况。

9)什么叫线程安全?servlet 是线程安全吗?

线程安全指的是在多线程环境下,对共享数据的访问操作不会导致数据出现异常或不一致的情况。线程安全的代码能够正确地处理多个线程并发访问共享数据的情况,保证数据的一致性和正确性。

对于 Servlet,Servlet 容器会为每个请求创建一个线程来处理,因此 Servlet 的实现需要是线程安全的。Servlet 容器会在多个线程之间共享同一个 Servlet 实例,因此 Servlet 类中的实例变量需要考虑线程安全性。

通常情况下,Servlet 应该遵循以下原则来确保线程安全:

  • 避免使用实例变量存储请求相关的数据,可以使用局部变量或者 synchronized 来处理共享数据。
  • 如果需要使用实例变量,确保对共享数据的访问是线程安全的,可以使用 synchronized 或其他线程安全的方式来保护数据访问。

10)在 Java 程序中怎么保证多线程的运行安全?

要保证多线程的运行安全,可以采取以下措施:

  1. 使用同步机制:使用 synchronized 关键字或 Lock 接口来保护共享数据的访问,确保在同一时刻只有一个线程可以访问共享资源。
  2. 使用线程安全的数据结构:使用 Java 提供的线程安全的数据结构,如 ConcurrentHashMap、ConcurrentLinkedQueue 等,避免手动加锁。
  3. 避免竞态条件:在编写多线程程序时,要注意避免竞态条件的发生,即多个线程同时对共享资源进行读写而导致数据不一致的情况。
  4. 使用 volatile 关键字:在需要保证变量可见性的情况下,可以使用 volatile 关键字来修饰变量,确保线程之间的数据同步。
  5. 使用线程池:合理使用线程池可以避免线程创建和销毁的开销,同时可以控制并发线程数量,提高程序的性能和稳定性。
  6. 避免死锁:在设计多线程程序时,要避免出现死锁情况,即多个线程相互等待对方释放资源而无法继续执行的情况。

通过以上措施,可以有效地保证多线程程序的运行安全,确保数据的一致性和正确性。

开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system

前后端总计已经 800+ Star,1.5W+ 访问!

⭐点赞⭐收藏⭐不迷路!⭐

相关推荐
万物得其道者成8 分钟前
React Zustand状态管理库的使用
开发语言·javascript·ecmascript
学步_技术13 分钟前
Python编码系列—Python抽象工厂模式:构建复杂对象家族的蓝图
开发语言·python·抽象工厂模式
【D'accumulation】27 分钟前
典型的MVC设计模式:使用JSP和JavaBean相结合的方式来动态生成网页内容典型的MVC设计模式
java·设计模式·mvc
wn53137 分钟前
【Go - 类型断言】
服务器·开发语言·后端·golang
试行42 分钟前
Android实现自定义下拉列表绑定数据
android·java
茜茜西西CeCe1 小时前
移动技术开发:简单计算器界面
java·gitee·安卓·android-studio·移动技术开发·原生安卓开发
Hello-Mr.Wang1 小时前
vue3中开发引导页的方法
开发语言·前端·javascript
救救孩子把1 小时前
Java基础之IO流
java·开发语言
WG_171 小时前
C++多态
开发语言·c++·面试
小菜yh1 小时前
关于Redis
java·数据库·spring boot·redis·spring·缓存