线程池的使用例子

---- 原文有参看其他博主博客 —
​ 在Java中提供了Executors类可以帮助我们快速构建一些线程池,下面是4种线程池的基本使用例子

  • MyTaskThread 类

    /**
     * MyTaskThread类,实现Runnable接口
     * @Author fx
     * @date 2019/08/16
     */
    public class MyTaskThread implements Runnable {
    
    
        @Override
        public void run() {
            // 这里写你的业务逻辑
            // ...
            System.out.println(Thread.currentThread().getName() + "线程执行了");
        }
    }
    
    
1.newFixThreadPool - 固定线程池

​ 创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

  • corePoolSize与maximumPoolSize相等,即其线程全为核心线程
  • keepAliveTime = 0 该参数默认对核心线程无效,而FixedThreadPool全部为核心线程;
  • workQueue 为LinkedBlockingQueue(无界阻塞队列),队列最大值为Integer.MAX_VALUE,很可能造成OOM(内存溢出)

构造方法:

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    /**
     * 此方法用于创建固定的线程池
     */
    public static void fixedPool(){
        // 创建固定数量的线程池
        ExecutorService pool = Executors.newFixedThreadPool(3);
        // 创建线程
        Runnable r1 = new MyTaskThread();
        Runnable r2 = new MyTaskThread();
        Runnable r3 = new MyTaskThread();
        // 将线程放入线程池中执行
        pool.execute(r1);
        pool.execute(r2);
        pool.execute(r3);
        // 待任务执行完成,关闭线程池
        pool.shutdown();
    }

执行结果:

pool-1-thread-2线程执行了
pool-1-thread-3线程执行了
pool-1-thread-1线程执行了

进程已结束,退出代码0

可以看出,放进线程池的3个线程都被执行了

2.newSingleThreadExecutor - 单一线程池

​ 创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

  • corePoolSize与maximumPoolSize参数都为1,表示只创建一个线程
  • keepAliveTime = 0 该参数默认对核心线程无效
  • 被FinalizableDelegatedExecutorService包装,表明SingleThreadExecutor被定以后,无法修改,做到了真正的Single

构造方法:

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    /**
     * 此方法用于创建单一线程池
     * 每次调用execute方法,其实最后都是调用了thread-1的run方法。
     */
    public static void singleThreadPool(){
        //创建单一线程池
        ExecutorService pool = Executors.newSingleThreadExecutor();
        // 创建线程
        Runnable r1 = new MyTaskThread();
        Runnable r2 = new MyTaskThread();
        Runnable r3 = new MyTaskThread();
        // 将线程放入线程池中执行
        pool.execute(r1);
        pool.execute(r2);
        pool.execute(r3);
        // 待任务执行完成,关闭线程池
        pool.shutdown();
    }

执行结果:

pool-1-thread-1线程执行了
pool-1-thread-1线程执行了
pool-1-thread-1线程执行了

进程已结束,退出代码0

虽然这里创建了3个线程,然而线程池里执行的其实还是thread1的run方法

3.newCachedThreadPool - 缓存线程池

​ 创建一个可缓存的线程池,可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制

  • corePoolSize = 0,maximumPoolSize = Integer.MAX_VALUE表明线程创建几乎无限制
  • keepAliveTime = 60s,线程空闲60s后自动结束
  • workQueue 为 SynchronousQueue 队列,表明有任务就创建线程,来着不拒

构造方法:

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    /**
     * 此方法用于创建缓存线程池
     * 这种方式的特点是:可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们
     */
    public static void cachedPool(){
        ExecutorService pool = Executors.newCachedThreadPool();
        // 创建线程
        Runnable r1 = new MyTaskThread();
        Runnable r2 = new MyTaskThread();
        Runnable r3 = new MyTaskThread();
        Runnable r4 = new MyTaskThread();
        // 将线程放入线程池中执行
        pool.execute(r1);
        pool.execute(r2);
        pool.execute(r3);
        pool.execute(r4);
        // 待任务执行完成,关闭线程池
        pool.shutdown();
    }

执行结果:

pool-1-thread-1线程执行了
pool-1-thread-4线程执行了
pool-1-thread-3线程执行了
pool-1-thread-2线程执行了

进程已结束,退出代码0
4.newScheduledThreadPool - 支持周期任务的线程池

​ 创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求

构造方法:

    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
    /**
     * 此方法用于创建支持定时任务的线程池
     */
    public static void schedulePool(){
        // 创建支持周期运行的线程池
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(4);
        // 创建线程
        Runnable r1 = new MyTaskThread();
        Runnable r2 = new MyTaskThread();
        // 将线程放入线程池中执行
        pool.execute(r1);
        // 带有延迟时间的执行,1秒后执行
        pool.schedule(r2,1000,TimeUnit.MILLISECONDS);
        // 待任务执行完成,关闭线程池
        pool.shutdown();
    }

执行结果

pool-1-thread-1线程执行了
// 这里中间间隔了1秒
pool-1-thread-2线程执行了

进程已结束,退出代码0
ThreadPoolExecutor类的使用探讨

​ 在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用Executors去创建,而要通过ThreadPoolExecutor方式,这一方面是由于jdk中Executor框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。

下面是自定义线程池使用例子:

    public static void main(String[] args) {
        // 核心线程池数量
        int corePoolSize = 2;
        // 最大线程池数量
        int maximumPoolSize = 4;
        // 空闲等待时间
        long keepAliveTime = 10;
        // 时间单位,秒
        TimeUnit unit = TimeUnit.SECONDS;
        // 有界阻塞队列
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
        // 创建线程的工厂,这里我们自定义一个自己的实现
        ThreadFactory threadFactory = new ThreadFactory() {
            private final AtomicInteger mThreadNum = new AtomicInteger(1);
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r, "my-thread-" + mThreadNum.getAndIncrement());
                System.out.println(t.getName() + " has been created");
                return t;
            }
        };
        // 拒绝策略,丢弃任务并抛出RejectedExecutionException
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();

        // 创建线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);
        // 预启动所有核心线程
        executor.prestartAllCoreThreads();

        // 创建线程
        for(int i=1;i<=10;i++){
            MyTaskThread taskThread = new MyTaskThread();
            executor.execute(taskThread);
        }

        try {
            // 阻塞主线程
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

执行结果:

my-thread-1 has been created
my-thread-2 has been created
my-thread-3 has been created
my-thread-1线程执行了
my-thread-2线程执行了
my-thread-2线程执行了
my-thread-4 has been created
my-thread-1线程执行了
my-thread-3线程执行了
my-thread-3线程执行了
my-thread-2线程执行了
my-thread-1线程执行了
my-thread-4线程执行了
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.aynu.fx.test.multithread.MyTaskThread@4d405ef7 rejected from java.util.concurrent.ThreadPoolExecutor@6193b845[Running, pool size = 4, active threads = 0, queued tasks = 0, completed tasks = 9]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
	at com.aynu.fx.test.multithread.MultiThreadTest.main(MultiThreadTest.java:48)

通过自定义线程池,我们可以更好的让线程池为我们所用,更加适应我的实际场景.

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用C#开发多线程应用程序时,线程池是一个非常有用的工具,它可以帮助我们更有效地管理和利用线程资源。下面是一个简单的线程池使用例子: ```csharp using System; using System.Threading; class Program { static void Main() { // 创建一个线程池 ThreadPool.QueueUserWorkItem(PrintMessage, "Hello, World!"); Console.WriteLine("Main thread does some other work."); // 等待一段时间,以便观察线程池中的线程执行任务 Thread.Sleep(2000); Console.WriteLine("Main thread finished."); // 需要在程序结束前调用一下,以确保所有任务都被执行完毕 ThreadPool.QueueUserWorkItem(WaitAndPrint, "This is the last message."); Console.ReadLine(); } static void PrintMessage(object state) { string message = (string)state; Console.WriteLine("PrintMessage: " + message); } static void WaitAndPrint(object state) { string message = (string)state; Thread.Sleep(1000); Console.WriteLine("WaitAndPrint: " + message); } } ``` 在上面的例子中,我们首先使用`ThreadPool.QueueUserWorkItem`方法将一个任务放入线程池中执行。然后,主线程继续执行其他工作。在等待一段时间后,我们可以看到线程池中的线程执行了我们放入的任务。 同时,我们还使用了`ThreadPool.QueueUserWorkItem`方法来放置一个最后的任务,以确保它会在程序结束前被执行。这是因为线程池中的任务可能不会立即执行,所以我们需要等待一段时间。 需要注意的是,使用线程池时,我们并不控制具体的线程创建和销毁过程,而是将任务交给线程池管理。这可以帮助我们更好地利用系统资源,并避免频繁地创建和销毁线程所带来的开销。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值