2025年最新并发知识,继承Thread类创建线程

 

Thread 类是 Java 提供的用于创建和控制线程的类。通过继承该类并重写其 run() 方法,可以创建一个新线程。

 

class MyThread extends Thread {

    @Override

    public void run() {

        System.out.println("Thread is running.");

    }

 

    public static void main(String[] args) {

        MyThread thread = new MyThread();

        thread.start(); // 启动线程

    }

}

 

实现Runnable接口创建线程

Runnable 接口是另一种常用的创建线程的方式。实现 Runnable 接口并重写 run() 方法,再通过 Thread 类来启动线程。

 

class MyRunnable implements Runnable {

    @Override

    public void run() {

        System.out.println("Thread is running.");

    }

 

    public static void main(String[] args) {

        MyRunnable myRunnable = new MyRunnable();

        Thread thread = new Thread(myRunnable);

        thread.start(); // 启动线程

    }

}

 

 

 通过Callable和FutureTask创建线程

Callable 是一个类似于 Runnable 的接口,但它允许任务有返回值,并且可以抛出异常。结合 Future 接口,可以获取任务执行的结果

 

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

 

class MyCallable implements Callable<Integer> {

    @Override

    public Integer call() throws Exception {

        return 42; // 返回值

    }

 

    public static void main(String[] args) throws Exception {

        ExecutorService executorService = Executors.newFixedThreadPool(1);

        Future<Integer> future = executorService.submit(new MyCallable());

        System.out.println("Result: " + future.get()); // 获取任务的返回值

        executorService.shutdown();

    }

}

 

 

通过线程池创建线程 

线程池通过预先创建多个线程并复用这些线程来处理任务,从而减少了频繁创建和销毁线程的开销。线程池的使用更加高效,并且可以有效地控制并发数量,避免线程过多导致资源耗尽。(比较推荐)

 

1. 使用 Executors 工厂方法创建线程池

Java 提供了几个 Executors 工厂方法来创建不同类型的线程池。常见的有:

 

1.newFixedThreadPool(int nThreads):创建一个固定大小的线程池。

2.newCachedThreadPool():创建一个可缓存的线程池,线程池的大小是动态的,根据需求创建新线程。

3.newSingleThreadExecutor():创建一个只有一个线程的线程池。

4.newScheduledThreadPool(int corePoolSize):创建一个可以定时执行任务的线程池。

 

创建一个固定大小线程池的代码

 

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

 

public class ThreadPoolExample {

    public static void main(String[] args) {

        // 创建一个固定大小的线程池,大小为 3

        ExecutorService executorService = Executors.newFixedThreadPool(3);

 

        // 提交多个任务到线程池

        for (int i = 0; i < 5; i++) {

            executorService.submit(new RunnableTask(i));

        }

 

        // 关闭线程池

        executorService.shutdown();

    }

}

 

class RunnableTask implements Runnable {

    private int taskId;

 

    public RunnableTask(int taskId) {

        this.taskId = taskId;

    }

 

    @Override

    public void run() {

        System.out.println("Task " + taskId + " is being executed by " + Thread.currentThread().getName());

        try {

            Thread.sleep(1000); // 模拟任务执行

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

}

 

 

Executors.newFixedThreadPool(3) 创建一个线程池,最多同时运行 3 个线程。如果任务数量超过线程池大小,剩余的任务将等待有线程空闲时执行。

executorService.submit(new RunnableTask(i)) 提交任务到线程池。

executorService.shutdown() 用于关闭线程池,当所有任务完成后,线程池会被关闭。

 

创建一个缓存的线程池

 

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

 

public class CachedThreadPoolExample {

    public static void main(String[] args) {

        // 创建一个可缓存的线程池

        ExecutorService executorService = Executors.newCachedThreadPool();

 

        // 提交多个任务到线程池

        for (int i = 0; i < 5; i++) {

            executorService.submit(new RunnableTask(i));

        }

 

        // 关闭线程池

        executorService.shutdown();

    }

}

 

class RunnableTask implements Runnable {

    private int taskId;

 

    public RunnableTask(int taskId) {

        this.taskId = taskId;

    }

 

    @Override

    public void run() {

        System.out.println("Task " + taskId + " is being executed by " + Thread.currentThread().getName());

        try {

            Thread.sleep(1000); // 模拟任务执行

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

}

 

 

Executors.newCachedThreadPool() 创建一个线程池,该池的线程数可以根据任务需求动态增加,线程池中没有任务时会回收空闲线程。适用于执行短时间的异步任务,特别是当任务数量不可预测时。 

 

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;

 

public class ScheduledThreadPoolExample {

    public static void main(String[] args) {

        // 创建一个线程池,核心线程数为 2

        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

 

        // 创建一个任务

        Runnable task = () -> System.out.println("Task executed at: " + System.currentTimeMillis());

 

        // 定期每 3 秒执行一次任务

        scheduler.scheduleAtFixedRate(task, 0, 3, TimeUnit.SECONDS);

 

        // 或者,延迟执行任务,任务将在 5 秒后开始执行

        // scheduler.schedule(task, 5, TimeUnit.SECONDS);

    }

}

 

 

corePoolSize:指定线程池的核心线程数。即使在空闲状态下,核心线程也会保持在池中,直到线程池关闭。这个参数决定了线程池中至少会有多少个线程来处理任务。

ScheduledExecutorService:该线程池支持定时和周期性任务调度,可以通过 schedule() 方法来延迟执行任务,或者通过 scheduleAtFixedRate() 和 scheduleWithFixedDelay() 来定期执行任务。

 

2.自定义线程池

自定义线程池是根据需求来定制线程池的一种方式。通常,我们可以通过 ThreadPoolExecutor 来实现线程池的自定义,而不使用 Executors 工厂方法。ThreadPoolExecutor 提供了丰富的参数配置,使得我们可以灵活地创建符合需求的线程池。

 

ThreadPoolExecutor(int corePoolSize, 

                   int maximumPoolSize, 

                   long keepAliveTime, 

                   TimeUnit unit, 

                   BlockingQueue<Runnable> workQueue)

 

 

 corePoolSize:核心线程池大小,即线程池中始终保持的最小线程数。

maximumPoolSize:线程池能够创建的最大线程数。如果任务量大于核心线程数,线程池会创建更多的线程,直到达到这个最大值。

keepAliveTime:当线程池中的线程数超过核心线程数时,多余的线程在空闲时间达到 keepAliveTime 后会被终止。这个时间单位由 unit 参数指定。

unit:keepAliveTime 的时间单位,例如 TimeUnit.SECONDS、TimeUnit.MILLISECONDS 等。

workQueue:用于保存待执行任务的队列。常见的队列有 ArrayBlockingQueue(固定大小队列)、LinkedBlockingQueue(无限队列)、PriorityBlockingQueue(优先级队列)等。

 

示例:自定义线程池

 

import java.util.concurrent.*;

 

public class CustomThreadPool {

    public static void main(String[] args) {

        // 创建一个核心线程数为 2,最大线程数为 4,空闲线程存活时间为 60 秒,队列为无界队列的线程池

        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(

            2, // corePoolSize

            4, // maximumPoolSize

            60, // keepAliveTime

            TimeUnit.SECONDS, // keepAliveTime单位

            new LinkedBlockingQueue<>() // workQueue

        );

 

        // 创建一个任务

        Runnable task = () -> {

            System.out.println("Task executed by " + Thread.currentThread().getName());

        };

 

        // 提交 5 个任务到线程池

        for (int i = 0; i < 5; i++) {

            threadPool.submit(task);

        }

 

        // 关闭线程池

        threadPool.shutdown();

    }

}

 

 

线程池创建:

 

核心线程数设置为 2,即线程池中始终保持 2 个线程。

最大线程数设置为 4,意味着在高负载情况下,最多可以创建 4 个线程。

空闲线程在超过 60 秒没有任务时会被终止。

使用 LinkedBlockingQueue 作为任务队列,表示队列是一个无界队列,任务可以无限入队,直到线程池的最大线程数达到限制。

 

 

任务提交:

 

创建了一个任务,该任务只是输出当前线程的名字。

使用 submit() 方法将任务提交给线程池。

 

 

关闭线程池:

 

使用 shutdown() 方法优雅地关闭线程池。它会等待线程池中的所有任务执行完毕后才会关闭线程池。

 

其他自定义线程池参数

拒绝策略和线程工厂

 

 拒绝策略

 

当线程池无法处理更多任务时,可以设置拒绝策略。例如,使用 RejectedExecutionHandler 来定义任务被拒绝时的处理方式。常见的拒绝策略有:

 

ThreadPoolExecutor.AbortPolicy(默认):丢弃任务并抛出 RejectedExecutionException。

ThreadPoolExecutor.DiscardPolicy:丢弃任务但不抛出异常。

ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列中最旧的任务,然后重试提交新任务。

ThreadPoolExecutor.CallerRunsPolicy:由提交任务的线程来执行任务,而不是丢弃任务。

 

示例:带拒绝策略的线程池

 

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(

    2, // corePoolSize

    4, // maximumPoolSize

    60, // keepAliveTime

    TimeUnit.SECONDS, // keepAliveTime单位

    new LinkedBlockingQueue<>(2), // workQueue,容量为2的队列

    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:由调用者线程执行任务

);

 

 

线程工厂

 

示例:带线程工厂的线程池

 

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(

    2, // corePoolSize

    4, // maximumPoolSize

    60, // keepAliveTime

    TimeUnit.SECONDS, // keepAliveTime单位

    new LinkedBlockingQueue<>(), // workQueue

    new ThreadFactory() {

        @Override

        public Thread newThread(Runnable r) {

            Thread thread = new Thread(r);

            thread.setName("Custom-Thread-" + thread.getId()); // 设置线程名称

            return thread;

        }

    }

);

 

 

总结

自定义线程池通过 ThreadPoolExecutor 提供了高度的灵活性,允许你根据应用需求调整线程池的核心线程数、最大线程数、队列类型、拒绝策略等。常见的用途包括:

 

高并发任务的调度。

限制最大线程数避免过多线程导致性能瓶颈。

实现自定义任务队列来管理任务的执行顺序。

通过调整线程池的各个参数,你可以创建适应不同场景的线程池。

 

总结

其实归根结底就两种,一个是继承Thread类,一个是实现Runnable接口,至于其他的,也是基于这两个方法实现的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值