线程初始化与线程池详解

2024-05-01 18:50:00 浏览数 (1)

一、线程初始化方式

在Java中,线程的初始化主要有四种方式:

1. 继承Thread类

通过继承Thread类并重写其run()方法,可以创建并启动一个线程。这种方式简单直观,但Java不支持多继承,因此如果一个类已经继承了其他类,就不能再继承Thread类。

代码语言:java复制
public class MyThread extends Thread {  
    @Override  
    public void run() {  
        System.out.println("MyThread is running.");  
    }  
  
    public static void main(String[] args) {  
        MyThread thread = new MyThread();  
        thread.start(); // 启动线程  
    }  
}

2. 实现Runnable接口

通过实现Runnable接口并重写其run()方法,也可以创建线程。这种方式更加灵活,因为Java类可以实现多个接口。但是,与继承Thread类一样,这种方式也无法直接获取线程的运算结果。

代码语言:java复制
public class MyRunnable implements Runnable {  
    @Override  
    public void run() {  
        System.out.println("MyRunnable is running.");  
    }  
  
    public static void main(String[] args) {  
        Thread thread = new Thread(new MyRunnable());  
        thread.start(); // 启动线程  
    }  
}

3. 实现Callable接口 FutureTask

Callable接口与Runnable接口类似,但Callable可以返回执行结果,并且可以声明抛出异常。FutureTask类实现了Future和Runnable接口,它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。这种方式虽然可以获取线程的运算结果并处理异常,但不利于控制服务器中的线程资源,可能导致服务器资源耗尽。

代码语言:java复制
import java.util.concurrent.*;  
  
public class MyCallable implements Callable<String> {  
    @Override  
    public String call() throws Exception {  
        return "MyCallable result";  
    }  
  
    public static void main(String[] args) throws ExecutionException, InterruptedException {  
        ExecutorService executor = Executors.newSingleThreadExecutor();  
        FutureTask<String> futureTask = new FutureTask<>(new MyCallable());  
        executor.submit(futureTask);  
          
        // 主线程等待子线程执行完毕并获取结果  
        String result = futureTask.get();  
        System.out.println(result); // 输出 "MyCallable result"  
          
        executor.shutdown(); // 关闭线程池  
    }  
}

4. 使用线程池

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的ThreadFactory创建一个新线程。通过线程池,我们可以更好地控制和管理线程资源,提高系统性能和稳定性。

代码语言:java复制
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
  
public class ThreadPoolExample {  
    public static void main(String[] args) {  
        ExecutorService executor = Executors.newFixedThreadPool(3); // 创建一个固定大小的线程池  
  
        for (int i = 0; i < 5; i  ) {  
            final int taskId = i;  
            executor.submit(() -> {  
                System.out.println("Task "   taskId   " is running by "   Thread.currentThread().getName());  
            });  
        }  
  
        executor.shutdown(); // 关闭线程池  
    }  
}

二、线程池的七大参数

在Java中,线程池的核心是ThreadPoolExecutor类,它提供了七个参数来配置线程池的行为:

  1. corePoolSize:核心线程数,即线程池中的常驻线程数。即使这些线程在空闲时也不会被销毁。
  2. maximumPoolSize:线程池允许的最大线程数。当队列满了且已创建的线程数小于maximumPoolSize,则线程池会再创建新的线程执行任务。
  3. keepAliveTime:当线程数大于核心线程数时,这是多余的空闲线程在终止前等待新任务的最长时间。
  4. unit:keepAliveTime参数的时间单位,通常是TimeUnit.MILLISECONDS。
  5. workQueue:用于保存等待执行的任务的阻塞队列。
  6. threadFactory:用于创建新线程的线程工厂,可以通过自定义的ThreadFactory来创建具有特定名称、优先级、是否为守护线程等的线程。
  7. handler:当线程池无法处理新任务时使用的饱和策略。
代码语言:java复制
import java.util.concurrent.*;  
  
public class ThreadPoolExecutorExample {  
    public static void main(String[] args) {  
        int corePoolSize = 2; // 核心线程数  
        int maximumPoolSize = 5; // 最大线程数  
        long keepAliveTime = 60L; // 空闲线程的存活时间  
        TimeUnit unit = TimeUnit.SECONDS; // 时间单位  
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10); // 任务队列  
        ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 线程工厂  
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); // 拒绝策略  
  
        ThreadPoolExecutor executor = new ThreadPoolExecutor(  
                corePoolSize,  
                maximumPoolSize,  
                keepAliveTime,  
                unit,  
                workQueue,  
                threadFactory,  
                handler  
        );  
  
        // 提交任务到线程池  
        executor.execute(() -> System.out.println("Task executed by thread pool."));  
  
        executor.shutdown(); // 关闭线程池  
    }  
}

三、常见的线程池类型

Java的java.util.concurrent包提供了几种常见的线程池实现:

FixedThreadPool:固定大小的线程池,它的核心线程数和最大线程数都是指定的,并且工作队列没有大小限制。

代码语言:txt复制
ExecutorService executor = Executors.newFixedThreadPool(5); // 创建固定大小的线程池

CachedThreadPool:可缓存的线程池,它的核心线程数为0,最大线程数为Integer.MAX_VALUE,工作队列是SynchronousQueue。这种线程池适合执行大量的耗时较少的任务。

代码语言:txt复制
ExecutorService executor = Executors.newCachedThreadPool(); // 创建可缓存的线程池

ScheduledThreadPool:定长线程池,支持定时及周期性任务执行。

代码语言:txt复制
ExecutorService executor = Executors.newCachedThreadPool(); // 创建可缓存的线程池

SingleThreadExecutor:单线程化的Executor,它使用单一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

代码语言:txt复制
ExecutorService executor = Executors.newSingleThreadExecutor(); // 创建单线程化的Executor

0 人点赞