线程池使用

本文介绍了线程池的概念,强调了线程池在减少线程创建和销毁开销中的作用。文章列举了Java中Executors类提供的五种线程池类型:newCachedThreadPool用于短期异步任务,newFixedThreadPool保持固定数量线程,newSingleThreadExecutor确保任务按顺序执行,newScheduledThreadPool支持定时及周期性任务,newSingleThreadScheduledExecutor是其单线程版。每种类型的线程池特点和应用场景都有详细说明。
摘要由CSDN通过智能技术生成

线程池(来自百度百科)

一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 例如,线程数一般取cpu数量+2比较合适,线程数过多会导致额外的线程切换开销。任务调度以执行线程的常见方法是使用同步队列,称作任务队列。池中的线程等待队列中的任务,并把执行完的任务放入完成队列中。

常见线程池

在Java中可以使用Executors类来创建线程池,Executors是静态工厂的功能,生产各种类型线程池。

1、newCachedThreadPool

创建一个可缓存的线程池。需要使用到线程时,会先从线程池中查找是否存在空闲的线程,如果没有线程可用,线程池能够根据需求创建新线程并放入线程池中,如果有线程可用,则直接使用可用的线程。线程执行完任务后,不会立即回收,会再次放回线程池,可以重用,缓存的线程60秒未使用则会被终止并移除。该线程池通常用于执行许多短期异步任务,能够有效提高程序的性能。

package com.su.mybatis.oracle.controller;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
 
    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for(int i = 0;i<10;i++){
            final int num  = i;
//            try {
//                Thread.sleep(100);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num);
                }
            });
        }
        cachedThreadPool.shutdown();
        System.out.println("main执行完成");
    }
}

运行结果:

pool-1-thread-1正在执行,num = 0
pool-1-thread-2正在执行,num = 1
pool-1-thread-1正在执行,num = 7
pool-1-thread-3正在执行,num = 2
pool-1-thread-2正在执行,num = 8
main执行完成
pool-1-thread-4正在执行,num = 3
pool-1-thread-6正在执行,num = 5
pool-1-thread-7正在执行,num = 6
pool-1-thread-5正在执行,num = 4
pool-1-thread-8正在执行,num = 9

每次for循环中Thread.sleep(100);,运行结果:

pool-1-thread-1正在执行,num = 0
pool-1-thread-1正在执行,num = 1
pool-1-thread-1正在执行,num = 2
pool-1-thread-1正在执行,num = 3
pool-1-thread-1正在执行,num = 4
pool-1-thread-1正在执行,num = 5
pool-1-thread-1正在执行,num = 6
pool-1-thread-1正在执行,num = 7
pool-1-thread-1正在执行,num = 8
pool-1-thread-1正在执行,num = 9
main执行完成

2、newFixedThreadPool

创建一个线程数量固定的线程池,线程池会重用运行的线程来执行在共享的无边界队列上的任务。指定的线程数量n即线程的最大并发数,也就是说,在任何时候,至多n个线程主动处理任务。如果在所有线程都处于活动状态时提交了其他任务,则它们将在队列中等待线程可用。如果任何线程在关闭之前的执行过程中由于失败而终止,则在需要执行后续任务时将使用新线程来代替它。线程池中的线程将一直存在,直到主动关闭线程池。

package com.su.mybatis.oracle.controller;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
 
    public static void main(String[] args) {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
        for(int i = 0;i<10;i++){
            final int num  = i;
            fixedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num);
                }
            });
        }
        fixedThreadPool.shutdown();
        System.out.println("main执行完成");
    }
}

运行结果:

pool-1-thread-1正在执行,num = 0
pool-1-thread-2正在执行,num = 1
main执行完成
pool-1-thread-3正在执行,num = 2
pool-1-thread-1正在执行,num = 5
pool-1-thread-2正在执行,num = 4
pool-1-thread-2正在执行,num = 8
pool-1-thread-2正在执行,num = 9
pool-1-thread-4正在执行,num = 3
pool-1-thread-1正在执行,num = 7
pool-1-thread-3正在执行,num = 6

 3、newSingleThreadExecutor

创建一个单线程的线程池。(无边界队列中)所有任务都是通过这一个线程来执行,所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个单线程由于意外(eg:执行失败)而终止,并且需要执行后续任务,则会新线程将取代它。

package com.su.mybatis.oracle.controller;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
 
    public static void main(String[] args) {
        ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
        for(int i = 0;i<5;i++){
            final int num  = i;
            singleThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num);
                }
            });
        }
        singleThreadPool.shutdown();
        System.out.println("main执行完成");
    }
}

运行结果:

main执行完成
pool-1-thread-1正在执行,num = 0
pool-1-thread-1正在执行,num = 1
pool-1-thread-1正在执行,num = 2
pool-1-thread-1正在执行,num = 3
pool-1-thread-1正在执行,num = 4

 4、newScheduledThreadPool

 创建一个线程数量固定的线程池,可以定时或者周期性执行任务。使用继承ExecutorService的ScheduledExecutorService类。

1)、schedule,延迟执行。

package com.su.mybatis.oracle.controller;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Test {
 
    public static void main(String[] args) {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
        for(int i = 0;i<3;i++){
            final int num  = i;
            final long time1  = System.currentTimeMillis();
            scheduledThreadPool.schedule(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num
                            + ",延时:" + (System.currentTimeMillis()-time1) + "ms");
                }
            }, 2, TimeUnit.SECONDS);//延时2秒执行
        }
        scheduledThreadPool.shutdown();
        System.out.println("main执行完成");
    }
}

运行结果:

main执行完成
pool-1-thread-3正在执行,num = 2,延时:2002ms
pool-1-thread-1正在执行,num = 0,延时:2001ms
pool-1-thread-2正在执行,num = 1,延时:2002ms

2)、scheduleAtFixedRate,延时定时执行,上一个任务开始执行的时间 + 周期时间 = 下一个任务的开始时间。

package com.su.mybatis.oracle.controller;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Test {
 
    public static void main(String[] args) {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
        for(int i = 0;i<3;i++){
            final int num  = i;
            final long time1  = System.currentTimeMillis();
            scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(300);//线程休眠300毫秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num
                            + ",延时:" + (System.currentTimeMillis()-time1) + "ms");
                }
            }, 1, 2, TimeUnit.SECONDS);//延时2秒执行
        }
    }
}

运行结果:

pool-1-thread-1正在执行,num = 0,延时:1305ms
pool-1-thread-3正在执行,num = 2,延时:1302ms
pool-1-thread-2正在执行,num = 1,延时:1303ms
pool-1-thread-2正在执行,num = 1,延时:3303ms
pool-1-thread-1正在执行,num = 2,延时:3302ms
pool-1-thread-3正在执行,num = 0,延时:3304ms

3)、 scheduleWithFixedDelay,延时定时执行,上一个任务结束时间 + 周期时间 = 下一个任务的开始时间。

package com.su.mybatis.oracle.controller;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Test {
 
    public static void main(String[] args) {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
        for(int i = 0;i<3;i++){
            final int num  = i;
            final long time1  = System.currentTimeMillis();
            scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(300);//线程休眠300毫秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num
                            + ",延时:" + (System.currentTimeMillis()-time1) + "ms");
                }
            }, 1, 2, TimeUnit.SECONDS);//延时2秒执行
        }
    }
}

 运行结果:

pool-1-thread-1正在执行,num = 0,延时:1304ms
pool-1-thread-3正在执行,num = 2,延时:1301ms
pool-1-thread-2正在执行,num = 1,延时:1301ms
pool-1-thread-2正在执行,num = 2,延时:3604ms
pool-1-thread-3正在执行,num = 0,延时:3607ms
pool-1-thread-1正在执行,num = 1,延时:3604ms

5、newSingleThreadScheduledExecutor

 创建单线程的线程池,可以定时或者周期性执行任务。与4中的区别是它是单线程。

1)、schedule,延时执行

package com.su.mybatis.oracle.controller;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Test {
 
    public static void main(String[] args) {
        ScheduledExecutorService singleThreadScheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
        for(int i = 0;i<3;i++){
            final int num  = i;
            final long time1  = System.currentTimeMillis();
            singleThreadScheduledThreadPool.schedule(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num
                            + ",延时:" + (System.currentTimeMillis()-time1) + "ms");
                }
            }, 2, TimeUnit.SECONDS);//延时2秒执行
        }
        singleThreadScheduledThreadPool.shutdown();
        System.out.println("main执行完成");
    }
}

 运行结果:

main执行完成
pool-1-thread-1正在执行,num = 0,延时:2002ms
pool-1-thread-1正在执行,num = 1,延时:2000ms
pool-1-thread-1正在执行,num = 2,延时:2000ms

2)、scheduleAtFixedRate,延时定时执行,上一个任务开始执行的时间 + 周期时间 = 下一个任务的开始时间。

package com.su.mybatis.oracle.controller;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Test {
 
    public static void main(String[] args) {
        ScheduledExecutorService singleThreadScheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
        for(int i = 0;i<3;i++){
            final int num  = i;
            final long time1  = System.currentTimeMillis();
            singleThreadScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(300);//线程休眠300毫秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num
                            + ",延时:" + (System.currentTimeMillis()-time1) + "ms");
                }
            }, 1, 2, TimeUnit.SECONDS);//延时1秒,每2秒执行一次
        }
    }
}

 运行结果:

pool-1-thread-1正在执行,num = 0,延时:1302ms
pool-1-thread-1正在执行,num = 1,延时:1603ms
pool-1-thread-1正在执行,num = 2,延时:1905ms
pool-1-thread-1正在执行,num = 0,延时:3303ms
pool-1-thread-1正在执行,num = 1,延时:3603ms
pool-1-thread-1正在执行,num = 2,延时:3904ms

3)、scheduleWithFixedDelay,延时定时执行,上一个任务结束时间 + 周期时间 = 下一个任务的开始时间。

package com.su.mybatis.oracle.controller;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Test {
 
    public static void main(String[] args) {
        ScheduledExecutorService singleThreadScheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
        for(int i = 0;i<3;i++){
            final int num  = i;
            final long time1  = System.currentTimeMillis();
            singleThreadScheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(300);//线程休眠300毫秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在执行,num = " + num
                            + ",延时:" + (System.currentTimeMillis()-time1) + "ms");
                }
            }, 1, 2, TimeUnit.SECONDS);//延时1秒,每2秒执行一次
        }
    }
}

运行结果:

pool-1-thread-1正在执行,num = 0,延时:1304ms
pool-1-thread-1正在执行,num = 1,延时:1602ms
pool-1-thread-1正在执行,num = 2,延时:1902ms
pool-1-thread-1正在执行,num = 0,延时:3607ms
pool-1-thread-1正在执行,num = 1,延时:3905ms
pool-1-thread-1正在执行,num = 2,延时:4205ms

 以上就是常用线程池的使用方法,根据不同场景使用不同的线程池。

 

 

如果有写的不对的地方,请大家多多批评指正,非常感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值