Java-线程池
文章目录
Java线程池是一种用于优化线程管理的技术,可以避免由于创建和销毁线程带来的开销,提高应用程序的性能和响应速度。Java线程池主要有四种类型,分别是固定线程池、可缓存线程池、定时线程池和单一线程池。下面将分别介绍这四种线程池并给出相应的实例代码。
Java线程池是Java中的一个重要概念,它是一种用于管理和复用线程的机制。在Java应用程序中,线程池可以提高程序的性能,减少线程的创建和销毁次数,降低线程的开销,提高系统的响应速度。
Java线程池的基本原理是将一组线程放入一个线程池中,当需要执行任务时,从线程池中取出一个空闲的线程来执行任务,执行完任务后,线程不会立即销毁,而是返回线程池中等待下一次任务的到来。这样可以避免频繁地创建和销毁线程,从而提高程序的效率。
线程池的参数
Java线程池的实现方式有多种,最常见的是使用Java标准库中的ThreadPoolExecutor类。ThreadPoolExecutor类提供了一组灵活的参数,可以根据应用程序的需要来配置线程池的大小、线程的生命周期、任务队列的大小、拒绝策略等参数。
 
1.corePoolSize:线程池中用来工作的核心线程数量。
 2.maximumPoolSize:最大线程数,线程池允许创建的最大线程数。
 3.keepAliveTime:超出 corePoolSize 后创建的线程存活时间或者是所有线程最大存活时间,取决于配置。
 4.unit:keepAliveTime 的时间单位。
 5.workQueue:任务队列,是一个阻塞队列,当线程数达到核心线程数后,会将任务存储在阻塞队列中。
 6.threadFactory :线程池内部创建线程所用的工厂。
 7.handler:拒绝策略;当队列已满并且线程数量达到最大线程数量时,会调用该方法处理任务。
线程池的状态
线程池内部有 5 个常量来代表线程池的五种状态
private static final int RUNNING = -1 << COUNT_BITS;
 private static final int SHUTDOWN = 0 << COUNT_BITS;
 private static final int STOP = 1 << COUNT_BITS;
 private static final int TIDYING = 2 << COUNT_BITS;
 private static final int TERMINATED = 3 << COUNT_BITS;

线程池的运行原理

-  创建线程池,这时没有创建线程(懒惰),等待提交过来的任务请求,调用 execute 方法才会创建线程 
-  当调用 execute() 方法添加一个请求任务时,线程池会做如下判断: - 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务
- 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列
- 如果这时队列满了且正在运行的线程数量还小于 maximumPoolSize,那么会创建非核心线程立刻运行这个任务,对于阻塞队列中的任务不公平。这是因为创建每个 Worker(线程)对象会绑定一个初始任务,启动 Worker 时会优先执行
- 如果队列满了且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会启动饱和拒绝策略来执行
 
-  当一个线程完成任务时,会从队列中取下一个任务来执行 
-  当一个线程空闲超过一定的时间(keepAliveTime)时,线程池会判断:如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉,所以线程池的所有任务完成后最终会收缩到 corePoolSize 大小 
线程池的优缺点
主要优点包括:
-  提高程序的性能:线程池可以复用线程,减少线程的创建和销毁次数,降低线程的开销,从而提高程序的性能。 
-  控制线程的数量:线程池可以限制线程的数量,避免线程数量过多导致系统崩溃或运行缓慢。 
-  提高系统的响应速度:线程池可以提高系统的响应速度,当有任务到来时,可以立即执行任务,不需要等待线程的创建和启动。 
-  简化编程:使用线程池可以简化编程,开发人员不需要手动创建和管理线程,只需要把任务提交给线程池即可。 
主要缺点包括:
-  需要合理配置参数:线程池的性能和效果受到参数的影响,需要合理配置参数才能达到最佳效果。 
-  可能会导致死锁:线程池中的任务可能会互相等待,导致死锁的发生。 
-  可能会导致资源竞争:线程池中的线程可能会争夺共享资源,导致资源竞争的发生。 
-  可能会影响程序的可伸缩性:线程池的大小和任务队列的大小可能会影响程序的可伸缩性,需要合理配置才能达到最佳效果。 
线程池类型
1. 固定线程池(FixedThreadPool)
固定线程池是一种创建后不会自动关闭的线程池,可以在需要时向其中添加或删除线程。它的核心线程数在创建时指定,并在整个生命周期内保持不变。
实例代码:
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class FixedThreadPoolExample {
    public static void main(String[] args) {
        int corePoolSize = 5; // 核心线程数
        int maximumPoolSize = 10; // 最大线程数
        long keepAliveTime = 60L; // 空闲线程等待任务的最长时间(单位:秒)
        ExecutorService executorService = Executors.newFixedThreadPool(corePoolSize);
        for (int i = 0; i < 15; i++) {
            Runnable worker = new WorkerThread("" + i);
            executorService.execute(worker);
        }
        executorService.shutdown(); // 关闭线程池,但不立即关闭已提交的任务
    }
}
2. 可缓存线程池(CachedThreadPool)
可缓存线程池是一种可以根据需要自动创建和关闭线程的线程池,它的线程数可以动态调整。当线程池中的线程空闲一段时间后,会自动关闭。当有新任务提交时,如果线程池中的线程数已经关闭,会自动创建新的线程。
实例代码:
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class CachedThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 15; i++) {
            Runnable worker = new WorkerThread("" + i);
            executorService.execute(worker);
        }
        executorService.shutdown(); // 关闭线程池,但不立即关闭已提交的任务
    }
}
3. 定时线程池(ScheduledThreadPool)
定时线程池是一种可以在指定时间间隔内定时执行任务的线程池,它的核心线程数可以动态调整。它与可缓存线程池类似,但定时线程池可以指定任务的执行时间间隔,而可缓存线程池只能等待任务队列中的任务到达。
实例代码:
import java.util.concurrent.Executors;  
import java.util.concurrent.ScheduledExecutorService;  
import java.util.concurrent.TimeUnit;  
  
public class ScheduledThreadPoolExample {  
    public static void main(String[] args) {  
        // 创建一个定时线程池  
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);  
          
        // 提交任务到线程池,指定任务的执行时间间隔  
        executor.scheduleAtFixedRate(() -> {  
            System.out.println("Task is running on thread " + Thread.currentThread().getName());  
        }, 0, 2, TimeUnit.SECONDS);  
          
        // 关闭线程池  
        executor.shutdown();  
    }  
}
4.单线程线程池
单线程线程池只有一个核心线程,所有任务都会在这个核心线程上执行。当任务队列满了之后,如果核心线程已经执行完任务,则会创建新的非核心线程来执行任务。
实例代码:
import java.util.concurrent.Executors;  
import java.util.concurrent.ExecutorService;  
  
public class SingleThreadExecutorExample {  
    public static void main(String[] args) {  
        // 创建一个单线程的线程池  
        ExecutorService executor = Executors.newSingleThreadExecutor();  
          
        // 提交任务到线程池  
        for (int i = 1; i <= 5; i++) {  
            int taskId = i;  
            executor.submit(() -> {  
                System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());  
            });  
        }  
          
        // 关闭线程池  
        executor.shutdown();  
    }  
}
5.自定义线程池
除了以上四种常见的线程池类型之外,我们还可以根据自己的需求自定义线程池。下面是一个自定义线程池的示例代码:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class CustomThreadPool {
    private BlockingQueue<Runnable> taskQueue;
    private Thread[] workers;
    public CustomThreadPool(int numThreads) {
        taskQueue = new LinkedBlockingQueue<>();
        workers = new Thread[numThreads];
        for (int i = 0; i < numThreads; i++) {
            workers[i] = new Thread(new Worker());
            workers[i].start();
        }
    }
    public void execute(Runnable task) {
        try {
            taskQueue.put(task);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    private class Worker implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    Runnable task = taskQueue.take();
                    task.run();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
}
 
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!