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

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

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() 方法
相关文章
|
2月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
2月前
|
消息中间件 前端开发 NoSQL
面试官:线程池遇到未处理的异常会崩溃吗?
面试官:线程池遇到未处理的异常会崩溃吗?
75 3
面试官:线程池遇到未处理的异常会崩溃吗?
|
2月前
|
消息中间件 存储 前端开发
面试官:说说停止线程池的执行流程?
面试官:说说停止线程池的执行流程?
51 2
面试官:说说停止线程池的执行流程?
|
2月前
|
消息中间件 前端开发 NoSQL
面试官:如何实现线程池任务编排?
面试官:如何实现线程池任务编排?
33 1
面试官:如何实现线程池任务编排?
|
3月前
|
Java
【多线程面试题二十五】、说说你对AQS的理解
这篇文章阐述了对Java中的AbstractQueuedSynchronizer(AQS)的理解,AQS是一个用于构建锁和其他同步组件的框架,它通过维护同步状态和FIFO等待队列,以及线程的阻塞与唤醒机制,来实现同步器的高效管理,并且可以通过实现特定的方法来自定义同步组件的行为。
【多线程面试题二十五】、说说你对AQS的理解
|
3月前
|
Java
【多线程面试题十六】、谈谈ReentrantLock的实现原理
这篇文章解释了`ReentrantLock`的实现原理,它基于Java中的`AbstractQueuedSynchronizer`(AQS)构建,通过重写AQS的`tryAcquire`和`tryRelease`方法来实现锁的获取与释放,并详细描述了AQS内部的同步队列和条件队列以及独占模式的工作原理。
【多线程面试题十六】、谈谈ReentrantLock的实现原理
|
3月前
|
消息中间件 缓存 算法
Java多线程面试题总结(上)
进程和线程是操作系统管理程序执行的基本单位,二者有明显区别: 1. **定义与基本单位**:进程是资源分配的基本单位,拥有独立的内存空间;线程是调度和执行的基本单位,共享所属进程的资源。 2. **独立性与资源共享**:进程间相互独立,通信需显式机制;线程共享进程资源,通信更直接快捷。 3. **管理与调度**:进程管理复杂,线程管理更灵活。 4. **并发与并行**:进程并发执行,提高资源利用率;线程不仅并发还能并行执行,提升执行效率。 5. **健壮性**:进程更健壮,一个进程崩溃不影响其他进程;线程崩溃可能导致整个进程崩溃。
48 2
|
3月前
|
存储 安全 容器
【多线程面试题二十一】、 分段锁是怎么实现的?
这篇文章解释了分段锁的概念和实现方式,通过将数据分成多个段并在每段数据上使用独立锁,从而降低锁竞争,提高并发访问效率,举例说明了`ConcurrentHashMap`如何使用分段锁技术来实现高并发和线程安全。
【多线程面试题二十一】、 分段锁是怎么实现的?
|
3月前
|
安全 Java
【多线程面试题十九】、 公平锁与非公平锁是怎么实现的?
这篇文章解释了Java中`ReentrantLock`的公平锁和非公平锁的实现原理,其中公平锁通过检查等待队列严格按顺序获取锁,而非公平锁允许新线程有更高机会立即获取锁,两者都依赖于`AbstractQueuedSynchronizer`(AQS)和`volatile`关键字以及CAS技术来确保线程安全和锁的正确同步。
【多线程面试题十九】、 公平锁与非公平锁是怎么实现的?
|
3月前
|
存储 缓存 安全
Java多线程面试题总结(中)
Java内存模型(JMM)定义了程序中所有变量的访问规则与范围,确保多线程环境下的数据一致性。JMM包含主内存与工作内存的概念,通过8种操作管理两者间的交互,确保原子性、可见性和有序性。`synchronized`和`volatile`关键字提供同步机制,前者确保互斥访问,后者保证变量更新的可见性。多线程操作涉及不同状态,如新建(NEW)、可运行(RUNNABLE)等,并可通过中断、等待和通知等机制协调线程活动。`volatile`虽不确保线程安全,但能确保变量更新对所有线程可见。
19 0

相关实验场景

更多