57. 守护线程是什么?

守护线程(Daemon Thread)是一种特殊类型的线程,它的主要作用是为其他线程提供服务,当程序中只剩下守护线程时,虚拟机(JVM)将会退出。这意味着守护线程的运行状态不会影响程序的持续性,它的主要目的是辅助主线程或用户线程执行任务。

在Java中,可以通过调用线程的setDaemon(true)方法将一个线程设置为守护线程。需要注意的是,这个操作必须在启动线程之前完成,一旦线程开始执行,就不能将其设置为守护线程。

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

  1. 守护线程通常用于执行一些后台任务,如垃圾回收、日志记录、监控等。
  2. 当所有非守护线程(用户线程)结束时,虚拟机会退出,此时守护线程将会被强制终止,即使它们可能还在运行中。
  3. 守护线程不应持有任何需要关闭的资源,因为它们可能会在资源释放前被终止。
  4. 设置为守护线程后,该线程创建的子线程默认也是守护线程。

以下是一个简单的代码示例,展示如何创建并启动一个守护线程:

public class DaemonThreadExample {
    public static void main(String[] args) {
        // 创建一个线程对象,并设置为守护线程
        Thread daemonThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("Daemon thread is running...");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        daemonThread.setDaemon(true); // 设置为守护线程

        // 创建一个普通线程
        Thread userThread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println("User thread is running...");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("User thread is about to finish...");
            }
        });

        // 启动线程
        daemonThread.start();
        userThread.start();

        // 确保守护线程能够执行一段时间
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这个例子中,当用户线程执行完毕后,即使守护线程还在运行,程序也会结束,因为JVM中没有活跃的非守护线程了。

58. 创建线程有哪几种方式?

在Java中创建线程主要有两种方式:通过继承Thread类或者实现Runnable接口。除此之外,还可以通过Callable接口以及使用ExecutorService来创建线程。

  1. 通过继承Thread
    当一个类继承自Thread类时,它就具备了线程的能力。你可以重写run方法来定义线程的执行行为。

    class MyThread extends Thread {
        public void run() {
            System.out.println("This is my thread.");
        }
    }
    public class TestThread {
        public static void main(String args[]) {
            MyThread t1 = new MyThread();
            t1.start();
        }
    }
    
  2. 通过实现Runnable接口
    Runnable是一个函数式接口,这意味着你可以使用lambda表达式来创建一个线程。使用Runnable接口相较于继承Thread类来说更加灵活,因为Java不支持多重继承。

    class MyRunnable implements Runnable {
        public void run() {
            System.out.println("This is my runnable.");
        }
    }
    public class TestRunnable {
        public static void main(String args[]) {
            Thread t1 = new Thread(new MyRunnable());
            t1.start();
        }
    }
    
  3. 通过Callable接口
    Callable接口与Runnable接口相似,但它允许线程返回结果,并且能抛出异常。

    import java.util.concurrent.Callable;
    import java.util.concurrent.FutureTask;
    
    class MyCallable implements Callable<Integer> {
        public Integer call() {
            return 100;
        }
    }
    public class TestCallable {
        public static void main(String args[]) {
            FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());
            Thread thread = new Thread(futureTask);
            thread.start();
        }
    }
    
  4. 使用ExecutorService
    ExecutorService是Java并发包中的一个接口,它可以更简单地管理线程。你可以使用它来执行RunnableCallable任务。

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class TestExecutorService {
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newFixedThreadPool(10);
            executorService.execute(new MyRunnable()); // For Runnable
            executorService.submit(new MyCallable());  // For Callable
            executorService.shutdown();
        }
    }
    

以上就是创建线程的几种常见方式。每种方法都有其适用的场景,通常来说,实现Runnable接口和使用ExecutorService是最推荐的线程创建方式,因为它们更加灵活,并且可以更好地管理线程资源。

有帮助请点赞收藏呀~

领【150 道精选 Java 高频面试题】请 go 公众号:码路向前 。

04-16 08:24