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

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

四十三、线程的run()和start()有什么区别?

在Java中,run()方法和start()方法都是与线程(Thread)相关的方法,但它们的作用和行为有所不同:

  1. run()方法

    • run()方法是java.lang.Runnable接口的一部分,用于定义线程要执行的具体任务。当线程被创建并启动后,run()方法中的代码将被执行。
    • 如果直接调用一个线程对象的run()方法,那么这个线程并不会在新线程中执行,而是在调用run()方法的当前线程中执行,即它不会产生多线程的效果。
    class MyThread implements Runnable {
        public void run() {
            // 线程执行的代码
        }
    }
    MyThread t = new MyThread();
    t.run(); // 直接调用run()方法,不会创建新线程
  2. start()方法

    • start()方法是java.lang.Thread类的方法,用于启动新线程。当调用一个线程对象的start()方法时,线程将进入可运行状态,Java虚拟机将会在适当的时候调度它的运行。
    • start()方法实际上会调用线程的run()方法,但在此之前,它会先执行与线程创建和初始化相关的操作。这意味着run()方法中的代码将在新线程的上下文中执行。
    Thread thread = new Thread(new MyRunnable());
    thread.start(); // 启动新线程,将会调用MyRunnable的run()方法
  3. 线程的生命周期

    • start()方法被调用时,线程的生命周期开始,线程会进入到就绪状态(Runnable),等待JVM调度其执行。
    • 当线程的run()方法执行完成后,线程结束其生命周期,进入到终止状态(Terminated)。
  4. 使用场景

    • 如果你想创建一个线程来执行特定的任务,你应该使用start()方法来启动线程。
    • 如果你只是想在当前线程中执行某个任务,而不需要创建新线程,你可以直接调用run()方法。

总结

  • run()方法是线程执行体,定义了线程要执行的任务。
  • start()方法是线程的启动器,调用它才会在新线程中执行run()方法。
  • 调用run()方法不会启动新线程,而start()方法会启动新线程并调用run()方法。
  • 在使用线程时,应该优先使用start()方法来启动线程,而不是直接调用run()方法。

四十四、创建线程池有哪几种方式?

在Java中,创建线程池主要有以下几种方式,每种方式都适用于不同的场景,并提供了不同级别的控制和灵活性:

  1. 使用ExecutorsExecutors类提供了一些工厂方法来创建不同类型的线程池,这些方法内部封装了线程池的创建细节。

    • 固定大小的线程池

    • ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
    • 单线程的线程池

      ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    • 可缓存的线程池

      ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    • 定时以及单次调度线程池

      ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
  2. 使用ExecutorService接口的实现类: 直接创建java.util.concurrent包下ExecutorService接口的实现类的实例,如ThreadPoolExecutor

    int corePoolSize = 3;
    int maximumPoolSize = 10;
    long keepAliveTime = 1L;
    TimeUnit unit = TimeUnit.MINUTES;
    BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();
    ThreadFactory threadFactory = Executors.defaultThreadFactory();
    RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
    ExecutorService threadPool = new ThreadPoolExecutor(
        corePoolSize,
        maximumPoolSize,
        keepAliveTime,
        unit,
        workQueue,
        threadFactory,
        handler
    );
  3. 使用ScheduledThreadPool: 如果需要执行定时任务或具有固定延迟的任务,可以使用ScheduledThreadPool

    ScheduledExecutorService scheduledThreadPool = new ScheduledThreadPoolExecutor(3);
  4. 自定义线程池: 如果标准线程池不能满足需求,可以自定义线程池。这涉及到继承ThreadPoolExecutor类或者实现Executor接口。

    class MyThreadPool extends ThreadPoolExecutor {
        public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }
        // 自定义线程池的其他行为
    }
    MyThreadPool myThreadPool = new MyThreadPool(3, 10, 1L, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>());
  5. 使用Executor接口: 直接实现Executor接口,提供一个执行任务的方法。

    class MyExecutor implements Executor {
        public void execute(Runnable command) {
            // 创建并启动新线程来执行任务
        }
    }
    MyExecutor myExecutor = new MyExecutor();

总结

  • Executors类提供了简便的方法来创建预定义配置的线程池,适合大多数一般用途。
  • ExecutorService接口和ThreadPoolExecutor类提供了更多的定制选项,适合需要特定行为的线程池。
  • ScheduledThreadPool适用于需要执行定时或周期性任务的场景。
  • 自定义线程池提供了最大的灵活性,但也需要更多的编码工作。
  • 选择哪种方式创建线程池,取决于具体的应用需求和对线程池行为的控制程度。
  • 35
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值