赶紧收藏!2024 年最常见 100道 Java 基础面试题(十九)

上一篇地址:赶紧收藏!2024 年最常见 100道 Java 基础面试题(十八)-CSDN博客

三十七、守护线程是什么?

守护线程(Daemon Thread)是Java中的一种特殊类型的线程,它的目的是为其他线程的执行提供支持,比如垃圾回收线程就是一个典型的守护线程。守护线程与用户线程(User Thread,也就是非守护线程)的主要区别在于,当用户线程全部结束时,虚拟机(JVM)会退出,而守护线程的结束不会导致JVM的退出。

以下是守护线程的一些关键特点:

  1. 后台支持: 守护线程通常用于执行后台任务,如监控、内存管理、信号处理等。

  2. 生命周期: 守护线程的生命周期不会阻止JVM的退出。当所有用户线程都结束时,JVM会结束运行,即使守护线程还在运行。

  3. 创建方式: 创建守护线程与创建普通线程类似,但必须在调用Thread.start()之前,通过调用Thread.setDaemon(true)方法来设置线程为守护线程。

  4. 垃圾回收线程: Java虚拟机的垃圾回收线程是守护线程的一个例子。它们负责回收不再使用的对象,释放内存资源。

  5. JVM启动: JVM启动时会创建一些守护线程来处理如类加载、信号处理等后台任务。

  6. 结束守护线程: 守护线程与普通线程一样,可以通过Thread.interrupt()方法来中断,或者自然终止。

  7. 使用场景: 如果一个线程的任务是为其他线程提供服务,且这个服务不是必需的,那么这个线程可以被设置为守护线程。

  8. 示例代码

  9. public class DaemonThreadExample {
        public static void main(String[] args) {
            Thread daemonThread = new Thread(() -> {
                while (true) {
                    // 执行一些后台任务
                    System.out.println("Daemon thread is running");
                    try {
                        Thread.sleep(1000); // 暂停1秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break; // 如果线程被中断,则退出循环
                    }
                }
            });
    
            // 设置为守护线程
            daemonThread.setDaemon(true);
            daemonThread.start();
    
            // 主线程睡眠5秒后结束
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

在这个例子中,主线程在睡眠5秒后结束,守护线程继续运行直到主线程结束。如果将线程设置为守护线程,JVM将在主线程结束后退出,即使守护线程还在运行。

总结

  • 守护线程是为其他线程提供支持的后台线程,它们不会阻止JVM的退出。
  • 守护线程通常用于执行非关键的后台任务,如垃圾回收、日志记录等。
  • 通过Thread.setDaemon(true)方法可以在启动线程之前将其设置为守护线程。

三十八、创建线程有哪几种方式?

在Java中,创建线程主要有以下几种方式:

  1. 继承Thread: 通过让类继承java.lang.Thread类并重写其run()方法来创建线程。这种方式是Java最初提供的线程创建方法。

  2. public class MyThread extends Thread {
        public void run() {
            // 线程执行的代码
        }
    }
    MyThread t = new MyThread();
    t.start();
  3. 实现Runnable接口: 通过实现java.lang.Runnable接口并将其实例作为参数传递给Thread类的构造方法来创建线程。这是推荐的方式,因为它更易于扩展和实现回调。

  4. public class MyRunnable implements Runnable {
        public void run() {
            // 线程执行的代码
        }
    }
    Thread t = new Thread(new MyRunnable());
    t.start();
  5. 使用Callable接口和FutureCallable接口类似于Runnable,但它可以返回值和抛出异常。通过Callable任务可以获取线程执行的结果,通常与FutureFutureTask结合使用。

  6. public class MyCallable implements Callable<String> {
        public String call() {
            // 执行线程任务并返回结果
            return "Callable result";
        }
    }
    FutureTask<String> task = new FutureTask<>(new MyCallable());
    Thread t = new Thread(task);
    t.start();
    // 稍后获取任务结果
    String result = task.get(); // 这将阻塞直到任务完成
  7. 使用java.util.concurrentjava.util.concurrent包提供了更高级的线程和同步工具,如ExecutorServiceThreadPoolExecutorScheduledThreadPool等。这些工具可以帮助创建线程池,更高效地管理线程资源。

  8. ExecutorService executor = Executors.newFixedThreadPool(3);
    executor.submit(() -> {
        // 线程执行的代码
    });
    executor.shutdown(); // 关闭线程池
  9. 使用ThreadFactoryThreadFactory接口用于创建新线程,可以通过ExecutorService的实现类传递自己的ThreadFactory来创建具有特定属性的线程。

    ThreadFactory threadFactory = new ThreadFactory() {
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setPriority(Thread.MIN_PRIORITY);
            return t;
        }
    };
    ExecutorService executor = Executors.newFixedThreadPool(3, threadFactory);
  10. 使用ThreadLocalThreadLocal并不是用来创建线程的,但它与线程紧密相关,用于提供线程内的局部变量。在某些情况下,可能会与线程创建和执行逻辑一起使用。

每种方式都有其适用场景,选择哪一种取决于具体的应用需求。例如,如果需要线程返回结果,可以使用Callable;如果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值