金三银四面试题--多线程(一)

简介: 金三银四面试题--多线程

1. 使用多线程有什么好处?

多线程有多种好处,如下所示:

  • 即使程序的一部分被阻塞,也允许程序继续运行。
  • 与使用多个进程的传统并行程序相比,提高了性能。
  • 允许编写利用最大 CPU 时间的有效程序
  • 提高复杂应用程序或程序的响应能力。
  • 增加 CPU 资源的使用并降低维护成本。
  • 节省时间和并行任务。
  • 如果在单个线程中发生异常,它不会影响其他线程,因为线程是独立的。
  • 与同时执行多个进程相比,资源密集型更少。

2. Java中的线程是什么?

线程基本上是可以由调度程序独立管理的轻量级和最小的处理单元。线程被称为进程的一部分,它只是让程序与进程的其他部分或线程同时有效地执行。使用线程,可以以最简单的方式执行复杂的任务。它被认为是利用机器中可用的多个 CPU 的最简单方法。它们共享公共地址空间并且彼此独立。

3. Java实现线程的两种方式是什么?

在java中实现线程基本上有两种方法,如下所示:

  • 扩展线程

例子:

class MultithreadingDemo extends Thread 
{   
  public void run() 
 {   
     System.out.println("My thread is in running state.");    
 } 
  public static void main(String args[]) 
 {   
    MultithreadingDemoobj=new MultithreadingDemo();  
        obj.start();  
  }  
}

输出:

My thread is in running state.


  • 在 Java 中实现Runnable接口

示例

class MultithreadingDemo implements Runnable 
{  
   public void run() 
 {  
      System.out.println("My thread is in running state.");  
  }  
    public static void main(String args[]) 
 {  
      MultithreadingDemo obj=new MultithreadingDemo();   
      Threadtobj =new Thread(obj);       tobj.start();  
 }   
}

输出:

My thread is in running state.



4. 线程和进程有什么区别?

线程:它只是指特定进程的最小单元。它具有同时执行程序的不同部分(称为线程)的能力。

进程:它只是指正在执行的程序,即活动程序。可以使用 PCB(过程控制块)处理过程。


线 过程
它是进程子单元的子集。 它是一个包含多个线程的正在执行的程序。
在这种情况下,线程间通信更快、更便宜、更容易、更高效,因为线程共享它们所属进程的相同内存地址。 在这种情况下,进程间通信更慢、更昂贵、更复杂,因为每个进程都有不同的内存空间或地址。
这些更容易创建、轻量级并且开销更少。 这些很难创建,重量级,并且有更多的开销。
它需要更少的时间来创建、终止和上下文切换。 它需要更多的时间来创建、终止和上下文切换。
具有多个线程的进程使用较少的资源。 没有线程的进程使用更多资源。
线程是进程的一部分,因此它们相互依赖,但每个线程独立执行。 进程相互独立。
需要在线程中进行同步以避免意外情况或问题。 每个进程都不需要同步。
他们彼此共享数据和信息。 他们不相互共享数据。

5. 类的锁和对象锁有什么区别?

类锁:在java中,每个类都有一个唯一的锁,通常称为类级锁。这些锁是使用关键字“静态同步”实现的,可用于使静态数据线程安全。它通常在想要防止多个线程进入同步块时使用。

例子:


public class ClassLevelLockExample  
{    
  public void classLevelLockMethod()  
 {       
     synchronized (ClassLevelLockExample.class)  
       {         
            //DO your stuff here       
       }    
 } 
}

对象锁:在java中,每个对象都有一个唯一的锁,通常称为对象级锁。这些锁是使用关键字“synchronized”实现的,可用于保护非静态数据。它通常在想要同步非静态方法或块时使用,以便只有线程能够在给定的类实例上执行代码块。

示例 :

public class ObjectLevelLockExample  
{    
  public void objectLevelLockMethod()  
 {   
     synchronized (this)  
       {     
            //DO your stuff here   
       } 
 }
}

护进程基本上是 Java 中使用“线程类”的两种类型的线程。

用户线程(非守护线程):在 Java 中,用户线程具有特定的生命周期,其生命周期独立于任何其他线程。JVM(Java 虚拟机)在终止之前等待任何用户线程完成其任务。当用户线程完成时,JVM 会终止整个程序以及相关的守护线程。

守护线程:在Java中,守护线程基本上被称为服务提供者,为用户线程提供服务和支持。守护线程的线程类中基本上有两种可用的方法:setDaemon() 和 isDaemon()。

用户线程与守护线程

用户线程 守护线程
JVM 在终止前等待用户线程完成其任务。 JVM 在终止前不会等待守护线程完成其任务。
这些线程通常由用户创建,用于并发执行任务。 这些线程通常由 JVM 创建。
它们用于应用程序的关键任务或核心工作。 它们不用于任何关键任务,而是用于执行一些辅助任务。
这些线程被称为高优先级任务,因此需要在前台运行。 这些线程被称为低优先级线程,因此特别需要支持后台任务,如垃圾收集、释放未使用对象的内存等。


7.我们如何创建守护线程?


我们可以使用线程类setDaemon(true)在 java 中创建守护线程。它用于将当前线程标记为守护线程或用户线程。isDaemon()方法一般用于检查当前线程是否为守护进程。如果线程是守护进程,它将返回 true,否则返回 false。
示例
**说明 setDaemon() 和 isDaemon() 方法使用的程序。**

public class DaemonThread extends Thread 
{ 
   public DaemonThread(String name){ 
       super(name); 
   } 
   public void run() 
   {  
       // Checking whether the thread is Daemon or not 
       if(Thread.currentThread().isDaemon()) 
       {  
           System.out.println(getName() + " is Daemon thread");  
       }    
       else 
       {  
           System.out.println(getName() + " is User thread");  
       }  
   }   
   public static void main(String[] args) 
   {  
       DaemonThread t1 = new DaemonThread("t1"); 
       DaemonThread t2 = new DaemonThread("t2"); 
       DaemonThread t3 = new DaemonThread("t3");  
       // Setting user thread t1 to Daemon 
       t1.setDaemon(true);       
       // starting first 2 threads  
       t1.start();  
       t2.start();   
       // Setting user thread t3 to Daemon 
       t3.setDaemon(true);  
       t3.start();         
   }  
}

输出:

t1 is Daemon thread 
t3 is Daemon thread 
t2 is User threa

但是只能在start() 方法之前调用 setDaemon()方法,否则肯定会抛出 IllegalThreadStateException,如下所示:

public class DaemonThread extends Thread 
{ 
   public void run() 
   { 
       System.out.println("Thread name: " + Thread.currentThread().getName()); 
       System.out.println("Check if its DaemonThread: "  
                       + Thread.currentThread().isDaemon()); 
   } 
   public static void main(String[] args) 
   { 
       DaemonThread t1 = new DaemonThread(); 
       DaemonThread t2 = new DaemonThread(); 
       t1.start();         
       // Exception as the thread is already started 
       t1.setDaemon(true); 
       t2.start(); 
   } 
}

8. wait() 和 sleep() 方法是什么?


wait():顾名思义,它是一种非静态方法,它会导致当前线程等待并进入睡眠状态,直到其他一些线程为对象的监视器(锁)调用 notify() 或 notifyAll() 方法。它只是释放锁,主要用于线程间通信。它在对象类中定义,并且只能从同步上下文中调用。

synchronized(monitor) 
{ 
monitor.wait();       Here Lock Is Released by Current Thread  
}

sleep():顾名思义,它是一种静态方法,可以暂停或停止当前线程的执行一段时间。它在等待时不会释放锁,主要用于在执行时引入暂停。它在线程类中定义,无需从同步上下文中调用。

synchronized(monitor) 
{ 
Thread.sleep(1000);     Here Lock Is Held by The Current Thread 
//after 1000 milliseconds, the current thread will wake up, or after we call that is interrupt() method 
}

9. notify() 和 notifyAll() 有什么区别?


notify():它发送一个通知并且只唤醒一个线程而不是多个线程在对象的监视器上等待。


notifyAll():它发送通知并唤醒所有线程并允许它们竞争对象的监视器而不是单个线程。



10. 为什么 Object 类中存在 wait()、notify() 和 notifyAll() 方法?



我们知道每个对象都有一个监视器,它允许线程持有对象上的锁。但是线程类不包含任何监视器。线程通常通过调用对象的wait()方法等待对象的监视器(锁),并使用notify()或notifyAll()方法通知正在等待同一锁的其他线程。因此,这三个方法仅在对象上调用,并允许所有线程与在该对象上创建的每个线程进行通信


11.什么是Runnable和Callable接口?写出它们之间的区别


这两个接口一般都用于封装需要由另一个线程执行的任务。但是它们之间有一些区别,如下所示:

运行接口:这个接口基本上从一开始就在 Java 中可用。它仅用于在并发线程上执行代码。
可调用接口:这个接口基本上是作为并发包的一部分引入的新接口。它解决了可运行接口的限制以及一些重大变化,如泛型、枚举、静态导入、变量参数方法等。它使用泛型来定义对象的返回类型。

public interface Runnable  
{   
  public abstract void run(); 
}  
public interface Callable<V>  
{    
V call() throws Exception;  
}

可运行接口与可调用接口

可运行接口 可调用接口
它不返回任何结果,因此不能抛出检查异常。 它返回一个结果,因此可以抛出异常。
它不能传递给 invokeAll 方法。 它可以传递给 invokeAll 方法。
它是在 JDK 1.0 中引入的。 它是在 JDK 5.0 中引入的,因此在 Java 5 之前不能使用它。
它只是属于 Java.lang。 它只是属于 java.util.concurrent。
它使用 run() 方法来定义任务。 它使用 call() 方法来定义任务。
要使用此接口,需要重写 run() 方法。 要使用此接口,需要重写 call() 方法
相关文章
|
8月前
|
监控 Kubernetes Java
阿里面试:5000qps访问一个500ms的接口,如何设计线程池的核心线程数、最大线程数? 需要多少台机器?
本文由40岁老架构师尼恩撰写,针对一线互联网企业的高频面试题“如何确定系统的最佳线程数”进行系统化梳理。文章详细介绍了线程池设计的三个核心步骤:理论预估、压测验证和监控调整,并结合实际案例(5000qps、500ms响应时间、4核8G机器)给出具体参数设置建议。此外,还提供了《尼恩Java面试宝典PDF》等资源,帮助读者提升技术能力,顺利通过大厂面试。关注【技术自由圈】公众号,回复“领电子书”获取更多学习资料。
|
8月前
|
安全 Java 程序员
面试必看:如何设计一个可以优雅停止的线程?
嘿,大家好!我是小米。今天分享一篇关于“如何停止一个正在运行的线程”的面试干货。通过一次Java面试经历,我明白了停止线程不仅仅是技术问题,更是设计问题。Thread.stop()已被弃用,推荐使用Thread.interrupt()、标志位或ExecutorService来优雅地停止线程,避免资源泄漏和数据不一致。希望这篇文章能帮助你更好地理解Java多线程机制,面试顺利! 我是小米,喜欢分享技术的29岁程序员。欢迎关注我的微信公众号“软件求生”,获取更多技术干货!
210 53
|
7月前
|
数据采集 Java Linux
面试大神教你:如何巧妙回答线程优先级这个经典考题?
大家好,我是小米。本文通过故事讲解Java面试中常见的线程优先级问题。小明和小华的故事帮助理解线程优先级:高优先级线程更可能被调度执行,但并非越高越好。实际开发需权衡业务需求,合理设置优先级。掌握线程优先级不仅能写出高效代码,还能在面试中脱颖而出。最后,小张因深入分析成功拿下Offer。希望这篇文章能助你在面试中游刃有余!
120 4
面试大神教你:如何巧妙回答线程优先级这个经典考题?
|
7月前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
460 14
|
7月前
|
安全 Java 程序员
Java 面试必问!线程构造方法和静态块的执行线程到底是谁?
大家好,我是小米。今天聊聊Java多线程面试题:线程类的构造方法和静态块是由哪个线程调用的?构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节有助于掌握Java多线程机制。下期再见! 简介: 本文通过一个常见的Java多线程面试题,详细讲解了线程类的构造方法和静态块是由哪个线程调用的。构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节对掌握Java多线程编程至关重要。
130 13
|
7月前
|
缓存 安全 Java
面试中的难题:线程异步执行后如何共享数据?
本文通过一个面试故事,详细讲解了Java中线程内部开启异步操作后如何安全地共享数据。介绍了异步操作的基本概念及常见实现方式(如CompletableFuture、ExecutorService),并重点探讨了volatile关键字、CountDownLatch和CompletableFuture等工具在线程间数据共享中的应用,帮助读者理解线程安全和内存可见性问题。通过这些方法,可以有效解决多线程环境下的数据共享挑战,提升编程效率和代码健壮性。
234 6
|
8月前
|
安全 Java 程序员
面试直击:并发编程三要素+线程安全全攻略!
并发编程三要素为原子性、可见性和有序性,确保多线程操作的一致性和安全性。Java 中通过 `synchronized`、`Lock`、`volatile`、原子类和线程安全集合等机制保障线程安全。掌握这些概念和工具,能有效解决并发问题,编写高效稳定的多线程程序。
229 11
|
8月前
|
缓存 安全 算法
Java 多线程 面试题
Java 多线程 相关基础面试题
|
9月前
|
并行计算 算法 安全
面试必问的多线程优化技巧与实战
多线程编程是现代软件开发中不可或缺的一部分,特别是在处理高并发场景和优化程序性能时。作为Java开发者,掌握多线程优化技巧不仅能够提升程序的执行效率,还能在面试中脱颖而出。本文将从多线程基础、线程与进程的区别、多线程的优势出发,深入探讨如何避免死锁与竞态条件、线程间的通信机制、线程池的使用优势、线程优化算法与数据结构的选择,以及硬件加速技术。通过多个Java示例,我们将揭示这些技术的底层原理与实现方法。
461 3
|
10月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!