欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 美景 > Java并发 线程——针对实习面试

Java并发 线程——针对实习面试

2024/11/29 20:07:09 来源:https://blog.csdn.net/weixin_73527957/article/details/143988109  浏览:    关键词:Java并发 线程——针对实习面试

目录

  • Java并发 线程
    • 什么是线程和进程?
    • Java里面的线程和进程与操作系统中的线程和进程有什么区别?
    • 线程怎么创建的?
    • 线程怎么停止的?
    • Java线程的生命周期和状态?
      • 1. 新建(New)
      • 2. 就绪(Runnable)
      • 3. 运行(Running)
      • 4. 阻塞(Blocked)
      • 5. 等待(Waiting)
      • 6. 超时等待(Timed Waiting)
      • 7. 终止(Terminated)

Java并发 线程

在这里插入图片描述

什么是线程和进程?

以下是线程和进程的定义和它们在Java中的区别:

进程(Process)
进程是操作系统进行资源分配和调度的一个独立单位。它是应用程序运行的实例,拥有独立的内存空间。每个进程至少有一个线程,即主线程。进程的特点包括:

  1. 独立性:进程是独立运行的,拥有自己的内存空间。
  2. 资源拥有:每个进程都有自己的一套独立的地址空间,一般来说,进程间的资源是不共享的。
  3. 开销较大:创建和销毁进程需要较大的系统资源和时间。

在Java中,一个Java应用程序通常是一个进程,可以通过Runtime.getRuntime().exec()方法来启动新的进程。

线程(Thread)
线程是进程中的一个实体是被系统独立调度和分派的基本单位。线程自身基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如执行栈),但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。线程的特点包括:

  1. 轻量级:线程的创建和销毁开销相对较小。
  2. 资源共享:同一进程内的线程可以共享进程的资源,如内存空间。
  3. 执行路径:每个线程代表程序中的一个执行路径。

在Java中,线程可以通过实现Runnable接口或继承Thread类来创建线程的调度和执行是由JVM在操作系统的支持下完成的

Java中的线程和进程的区别

  1. 资源拥有:进程拥有独立的内存空间,而线程共享进程的内存空间。
  2. 创建和管理开销:进程的创建和管理开销比线程大。
  3. 通信方式:进程间通信(IPC)比线程间通信复杂,因为它们拥有独立的内存空间。
  4. 执行:进程至少有一个线程,即主线程,而线程是进程中执行的最小单元。
  5. 调度:线程的调度是由操作系统完成的,而进程的调度是由操作系统的调度器管理的。

在Java并发编程中,通常使用线程来实现多任务并发执行,因为线程的创建和管理开销较小,且可以共享进程资源,适合于提高程序的并发性和响应性。

Java里面的线程和进程与操作系统中的线程和进程有什么区别?

在计算机科学中,线程和进程的概念在操作系统层面和Java(或任何其他编程语言)层面上是相似的,但它们的实现和抽象层次有所不同。以下是操作系统中的线程和进程与Java中的线程和进程的主要区别:

操作系统层面

  1. 进程(Operating System Process)

    • 操作系统层面的进程是资源分配和拥有的最小单位,拥有独立的内存空间。
    • 进程是由操作系统直接管理的,操作系统负责进程的创建、调度和销毁。
    • 每个进程至少有一个线程,即主线程。
    • 进程间通信(IPC)需要特定的机制,如管道、信号、共享内存等。
  2. 线程(Operating System Thread)

    • 线程是进程中的一个实体,是CPU调度和执行的单位。
    • 线程自身拥有一点资源(如执行栈),但可以与同进程的其他线程共享进程的资源。
    • 线程由操作系统管理,操作系统负责线程的调度和执行。
    • 线程间通信相对简单,因为它们共享相同的内存空间。

Java层面

  1. Java进程(Java Process)

    • 在Java中,一个进程通常是指一个JVM实例。JVM是Java程序的运行环境,它负责加载类、执行字节码等。
    • Java程序通常在一个单独的JVM进程中运行,但也可以有多个JVM实例在同一个操作系统进程中运行。
    • Java进程的创建和管理通常是由操作系统完成的,但可以通过Java代码启动新的JVM进程(例如,使用Runtime.exec())。
  2. Java线程(Java Thread)

    • Java线程是Java程序中并发执行的最小单位,可以是用户创建的线程或由JVM创建的系统线程(如垃圾回收线程)。
    • Java线程的创建和管理是通过Java的Thread类和Runnable接口来实现的。
    • Java线程的调度是由JVM在操作系统的支持下完成的,但Java提供了自己的线程调度模型和API。
    • Java线程间通信可以通过共享对象和使用同步机制(如synchronized关键字、Lock接口等)来实现。

主要区别

  • 抽象层次:操作系统层面的线程和进程是更接近硬件的低层次抽象,而Java层面的线程和进程是更高层次的抽象,隐藏了底层的复杂性。
  • 管理:操作系统直接管理进程和线程的生命周期,而Java线程的生命周期管理是由JVM提供的。
  • 调度:操作系统负责进程和线程的调度,而Java线程的调度是由JVM在操作系统的调度基础上进行的。
  • 资源管理:操作系统负责资源的分配和管理,而Java通过JVM提供了一套自己的资源管理机制,如垃圾回收。

总的来说,Java中的线程和进程是建立在操作系统的线程和进程之上的,Java通过JVM提供了一套自己的抽象和API,使得开发者可以在不直接与操作系统交互的情况下进行并发编程。

线程怎么创建的?

在Java中创建线程通常有两种主要方式:继承Thread类、实现Runnable接口

继承Thread类

通过创建一个新的类继承Thread类,并覆盖其run方法来定义线程执行的任务。然后,通过创建该类的实例来创建一个新的线程。

class MyThread extends Thread {@Overridepublic void run() {// 线程执行的代码System.out.println("线程运行中...");}
}public class ThreadExample {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start(); // 启动线程}
}

实现Runnable接口

创建一个类实现Runnable接口,并实现其run方法。然后,将这个类的实例传递给Thread类的构造器,并创建Thread对象来启动线程。

class MyRunnable implements Runnable {@Overridepublic void run() {// 线程执行的代码System.out.println("线程运行中...");}
}public class ThreadExample {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);thread.start(); // 启动线程}
}

Lambda表达式(Java 8及以上)

从Java 8开始,可以使用Lambda表达式简化实现Runnable接口的过程。

public class ThreadExample {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("线程运行中...");});thread.start(); // 启动线程}
}

总结

  • 继承Thread类:这种方式简单直观,但一个类只能继承一个类,如果需要继承其他类,则不能使用这种方式。
  • 实现Runnable接口:这种方式更加灵活,允许一个类实现多个接口,是推荐的方式。
  • 使用Lambda表达式:在Java 8及以上版本中,可以使用Lambda表达式进一步简化线程的创建,适用于线程任务比较简单的情况。

在实际开发中,推荐使用实现Runnable接口的方式,因为它提供了更好的灵活性和扩展性。

线程怎么停止的?

在Java中,正确地停止一个线程是一个复杂的问题,因为Java并没有提供直接停止线程的方法。强行终止一个线程可能会导致程序处于不稳定的状态,因为线程可能在执行到一半的时候被中断,导致资源泄露或者数据不一致。以下是一些处理线程停止的常见方法:

1. 使用标志位控制线程结束

通常推荐的做法是使用一个标志位(boolean变量)来控制线程的运行。在run方法或者call方法中,周期性地检查这个标志位,如果标志位被设置为false,则退出运行循环,结束线程。

public class StoppableThread extends Thread {private volatile boolean running = true;public void run() {while (running) {// 执行线程任务}}public void stopRunning() {running = false;}
}

使用时,只需调用stopRunning()方法来设置标志位,线程会在下次循环检查时退出。

2. 使用中断机制

Java提供了中断机制来请求线程停止。当一个线程被中断时,它的中断状态会被设置为true。可以通过调用Thread.interrupt()来中断线程,线程可以通过检查Thread.interrupted()或者isInterrupted()来响应中断。

public class InterruptibleTask implements Runnable {public void run() {try {while (!Thread.currentThread().isInterrupted()) {// 执行任务}} catch (InterruptedException e) {// 线程在等待中被中断} finally {// 清理资源}}
}

3. 使用FutureExecutorService

如果你使用的是ExecutorService来管理线程,可以通过Future对象来请求取消任务。

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(new InterruptibleTask());// 请求取消任务
future.cancel(true); // 参数true表示如果任务正在运行,则中断它

cancel()方法的参数true表示如果任务正在运行,则中断它。

4. 使用shutdownNow()方法

如果你使用的是ExecutorService,可以使用shutdownNow()方法尝试停止所有任务。

ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(new Runnable() {public void run() {// 执行任务}
});// 尝试停止所有任务
List<Runnable> notExecutedTasks = executor.shutdownNow();

shutdownNow()会尝试立即停止所有正在执行的任务,并且返回等待执行的任务列表。

注意事项

  • 直接使用Thread.stop()Thread.suspend()Thread.resume()方法来停止、挂起和恢复线程是过时的,并且不推荐使用,因为它们不安全,可能会导致数据不一致或者其他问题。
  • 线程的停止应该由线程本身来控制,外部只能发送停止请求,线程需要检查这个请求并做出相应的响应。
  • 线程的清理工作应该在线程结束前完成,以避免资源泄露。

Java线程的生命周期和状态?

在Java中,线程的生命周期可以分为以下几个状态,每个状态代表线程在其生命周期中的不同阶段。理解这些状态有助于编写和调试多线程程序。以下是Java线程的生命周期和状态:

1. 新建(New)

当一个线程对象被创建时,它处于新建状态。此时,线程对象已经实例化,但还没有调用start()方法。

Thread thread = new Thread();

2. 就绪(Runnable)

当调用线程对象的start()方法后,线程进入就绪状态。此时,线程已经准备好运行,并等待CPU调度执行。注意,在Java中,就绪状态包括了操作系统层面的就绪和运行两种状态。

thread.start();

3. 运行(Running)

当线程获得CPU时间片并开始执行其run()方法时,线程进入运行状态。在一个多核处理器上,多个线程可以同时处于运行状态。

public void run() {// 线程执行的代码
}

4. 阻塞(Blocked)

当线程试图获取一个已经被其他线程持有的锁时,它进入阻塞状态。线程在阻塞状态下不会占用CPU时间,直到它能够获得所需的锁。

synchronized (someObject) {// 线程执行的代码
}

5. 等待(Waiting)

当线程等待另一个线程显式地唤醒它时,它进入等待状态。线程在等待状态下不会占用CPU时间,直到另一个线程调用notify()notifyAll()方法唤醒它。

synchronized (someObject) {someObject.wait();
}

6. 超时等待(Timed Waiting)

当线程在调用带有超时参数的方法(如Thread.sleep(long millis)Object.wait(long timeout)Thread.join(long millis)等)时,它进入超时等待状态。线程在超时等待状态下不会占用CPU时间,直到超时时间结束或被唤醒。

Thread.sleep(1000); // 线程休眠1秒

7. 终止(Terminated)

当线程的run()方法执行完毕或因异常退出时,线程进入终止状态。此时,线程生命周期结束,不再是可运行状态。

public void run() {// 线程执行的代码// 线程执行完毕后进入终止状态
}

状态转换示意图

以下是线程状态转换的示意图:

New -> Runnable -> Running -> (Blocked/Waiting/Timed Waiting) -> Runnable -> Terminated

代码示例

下面是一个简单的代码示例,展示了线程在不同状态之间的转换:

public class ThreadLifecycleDemo {public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {try {System.out.println("Thread is running...");Thread.sleep(1000); // 进入超时等待状态synchronized (this) {wait(); // 进入等待状态}} catch (InterruptedException e) {e.printStackTrace();}}});System.out.println("Thread state after creation: " + thread.getState()); // NEWthread.start();System.out.println("Thread state after calling start(): " + thread.getState()); // RUNNABLEtry {Thread.sleep(500); // 主线程休眠,确保子线程进入超时等待状态System.out.println("Thread state during sleep: " + thread.getState()); // TIMED_WAITINGsynchronized (thread) {thread.notify(); // 唤醒子线程}Thread.sleep(500); // 主线程再次休眠,确保子线程进入等待状态System.out.println("Thread state after notify(): " + thread.getState()); // WAITINGthread.join(); // 等待子线程终止System.out.println("Thread state after termination: " + thread.getState()); // TERMINATED} catch (InterruptedException e) {e.printStackTrace();}}
}

在这个示例中,我们创建了一个线程并演示了它在不同状态之间的转换。通过调用getState()方法,我们可以获取线程的当前状态。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com