线程池

为什么使用线程池

    线程缺乏统一管理,占用过多的系统资源。

  缺乏更多功能,如定时执行、定期执行

使用线程池的好处

   重用存在的线程,减少对象创建、消亡的开销

   有效控制最大并发数,提高系统资源使用率

   定时执行、定期执行

线程池所在包:java.util.concurrent

顶级接口是Executor,真正的线程池接口是ExecutorService

java.util.concurrent.Executors类提供创建线程池的方法

常用的方法:

newCachedThreadPool()

newFixedThreadPool(int nThreads)

newScheduledThreadPool(int corePoolSize)

newSingleThreadExecutor()

下面分别适用使用Executors类中这些静态方法创建线程:

创建带有缓存的线程池:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.util.concurrent.ExecutorService;
 
import static java.util.concurrent.Executors.*;
 
 
public class NewCachedThreadTest {
    public static void main(String[] args) {
 
        ExecutorService executorService = newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            executorService.execute(new MyRunnable(i));
//            try {
//                Thread.sleep(200);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
        }
    }
}
 
 
class MyRunnable implements Runnable{
 
    int nums;
 
    public MyRunnable(int nums) {
        this.nums = nums;
    }
 
    @Override
    public void run() {
        System.out.println("当前线程名:"+Thread.currentThread().getName()+";正在执行的任务编号:"+nums);
    }
}

当前线程名:pool-1-thread-1;正在执行的任务编号:0
当前线程名:pool-1-thread-1;正在执行的任务编号:1
当前线程名:pool-1-thread-1;正在执行的任务编号:2
当前线程名:pool-1-thread-1;正在执行的任务编号:3
当前线程名:pool-1-thread-1;正在执行的任务编号:4
当前线程名:pool-1-thread-1;正在执行的任务编号:5
当前线程名:pool-1-thread-1;正在执行的任务编号:6
当前线程名:pool-1-thread-1;正在执行的任务编号:7
当前线程名:pool-1-thread-1;正在执行的任务编号:8
当前线程名:pool-1-thread-1;正在执行的任务编号:9

如果我们将休眠时间注销掉,会看到有更多的线程参与到任务执行的过程中

当前线程名:pool-1-thread-3;正在执行的任务编号:2
当前线程名:pool-1-thread-7;正在执行的任务编号:6
当前线程名:pool-1-thread-6;正在执行的任务编号:5
当前线程名:pool-1-thread-5;正在执行的任务编号:4
当前线程名:pool-1-thread-4;正在执行的任务编号:3
当前线程名:pool-1-thread-1;正在执行的任务编号:0
当前线程名:pool-1-thread-2;正在执行的任务编号:1
当前线程名:pool-1-thread-10;正在执行的任务编号:9
当前线程名:pool-1-thread-9;正在执行的任务编号:8
当前线程名:pool-1-thread-8;正在执行的任务编号:7

使用线程池创建单线程:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
import static java.util.concurrent.Executors.newCachedThreadPool;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
 
 
public class NewSingleThreadTest {
    public static void main(String[] args) {
 
        ExecutorService executorService = newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            executorService.execute(new MyRunnable2(i));
        }
    }
}
 
 
class MyRunnable2 implements Runnable{
 
    int nums;
 
    public MyRunnable2(int nums) {
        this.nums = nums;
    }
 
    @Override
    public void run() {
        System.out.println("当前线程名:"+Thread.currentThread().getName()+";正在执行的任务编号:"+nums);
    }
}

当前线程名:pool-1-thread-1;正在执行的任务编号:0
当前线程名:pool-1-thread-1;正在执行的任务编号:1
当前线程名:pool-1-thread-1;正在执行的任务编号:2
当前线程名:pool-1-thread-1;正在执行的任务编号:3
当前线程名:pool-1-thread-1;正在执行的任务编号:4
当前线程名:pool-1-thread-1;正在执行的任务编号:5
当前线程名:pool-1-thread-1;正在执行的任务编号:6
当前线程名:pool-1-thread-1;正在执行的任务编号:7
当前线程名:pool-1-thread-1;正在执行的任务编号:8
当前线程名:pool-1-thread-1;正在执行的任务编号:9

创建固定线程数的线程池:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.util.concurrent.ExecutorService;
 
import static java.util.concurrent.Executors.newFixedThreadPool;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
 
 
public class NewFixedThreadTest {
    public static void main(String[] args) {
 
        ExecutorService executorService = newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            executorService.execute(new MyRunnable2(i));
        }
    }
}
 
 
class MyRunnable3 implements Runnable{
 
    int nums;
 
    public MyRunnable3(int nums) {
        this.nums = nums;
    }
 
    @Override
    public void run() {
        System.out.println("当前线程名:"+Thread.currentThread().getName()+";正在执行的任务编号:"+nums);
    }
}

  

当前线程名:pool-1-thread-1;正在执行的任务编号:0
当前线程名:pool-1-thread-2;正在执行的任务编号:1
当前线程名:pool-1-thread-3;正在执行的任务编号:2
当前线程名:pool-1-thread-2;正在执行的任务编号:4
当前线程名:pool-1-thread-2;正在执行的任务编号:6
当前线程名:pool-1-thread-1;正在执行的任务编号:3
当前线程名:pool-1-thread-2;正在执行的任务编号:7
当前线程名:pool-1-thread-3;正在执行的任务编号:5
当前线程名:pool-1-thread-2;正在执行的任务编号:9
当前线程名:pool-1-thread-1;正在执行的任务编号:8

创建带有定时任务的线程池:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
 
import static java.util.concurrent.Executors.newFixedThreadPool;
import static java.util.concurrent.Executors.newScheduledThreadPool;
 
 
public class NewScheduledThreadTest {
    public static void main(String[] args) {
 
        ScheduledExecutorService executorService = newScheduledThreadPool(3);
 
        System.out.println("=====================任务开始执行=======================");
 
        executorService.scheduleAtFixedRate(new MyRunnable4(),1,2, TimeUnit.SECONDS);
    }
}
 
 
class MyRunnable4 implements Runnable{
 
    @Override
    public void run() {
        System.out.println("当前线程名:"+Thread.currentThread().getName()+"-延时1秒钟执行,每两秒钟执行一次");
    }
}

  

=====================任务开始执行=======================
当前线程名:pool-1-thread-1-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-1-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-2-延时1秒钟执行,每两秒钟执行一次
当前线程名:pool-1-thread-3-延时1秒钟执行,每两秒钟执行一次

........

ThreadPoolExecutor构造器中常用的参数:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler)

1corePoolSize:核心线程数

        * 核心线程会一直存活,即使没有任务需要执行

        * 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理

        * 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭

 

2workQueue:任务队列容量(阻塞队列)

        * 当核心线程数达到最大时,新任务会放在队列中排队等待执行

 

3maximumPoolSize:最大线程数

        * 当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务

        * 当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常

 

4keepAliveTime:线程空闲时间

        * 当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize

        * 如果allowCoreThreadTimeout=true,则会直到线程数量=0

5、 unit:参数keepAliveTime的时间单位

6、 Handler表示当拒绝处理任务时的策略。当任务很多的时候,阻塞队列中的任务也满了的时候,如果还有任务来,这个时候,就需要使用拒绝策略来进行拒绝。

7、 threadFactory线程工厂,主要用来创建线程。

 

线程池的执行原理:  

 

 

 

 

当有12个任务需要被执行的时候,现在线程池中有5个核心线程,分别被安排了 1 2 3 4 5这几个任务执行,后面的6 7 8 9任务会被放到队列中进行排队等待,后面还有任务10 11 12还没有处理,这个时候会在线程池中再创建两个线程来执行任务10 11,这个时候线程池中的线程数已经达到了最大线程数,任务12就会被拒绝策略拒绝掉(因为线程池满了,队列也满了,没有地方存放或者执行任务12了),就只能拒绝掉了。当任务没有那么多的时候,核心线程能处理的时候,经过keepAliveTime的时间,会将多创建出来的2个线程销毁掉,保留核心线程。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
 
import static java.util.concurrent.Executors.newCachedThreadPool;
 
 
public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
 
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                5,
                7,
                300,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(4));
        for (int i = 1; i <= 12; i++) {
            executor.execute(new MyRunnable5(i));
            System.out.println("线程池中的线程数:"+executor.getPoolSize()
                    +",队列中等待执行任务的任务数:"+executor.getQueue().size()
                    +",已经执行完的任务数:"+executor.getCompletedTaskCount());
        }
        executor.shutdown();//所有任务都执行完毕之后,销毁线程池
    }
}
 
 
class MyRunnable5 implements Runnable {
 
    int nums;//当前正在执行的任务编号
 
    public MyRunnable5(int nums) {
        this.nums = nums;
    }
 
    @Override
    public void run() {
        System.out.println("任务" + nums + "开始执行");
        try {
            Thread.sleep(200);//假设执行一个任务需要耗费的时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("任务" + nums + "执行完毕");
    }
}

 

  

任务1开始执行

线程池中的线程数:1,队列中等待执行任务的任务数:0,已经执行完的任务数:0

线程池中的线程数:2,队列中等待执行任务的任务数:0,已经执行完的任务数:0

线程池中的线程数:3,队列中等待执行任务的任务数:0,已经执行完的任务数:0

任务2开始执行

任务3开始执行

线程池中的线程数:4,队列中等待执行任务的任务数:0,已经执行完的任务数:0

任务4开始执行

线程池中的线程数:5,队列中等待执行任务的任务数:0,已经执行完的任务数:0

任务5开始执行

线程池中的线程数:5,队列中等待执行任务的任务数:1,已经执行完的任务数:0

线程池中的线程数:5,队列中等待执行任务的任务数:2,已经执行完的任务数:0

线程池中的线程数:5,队列中等待执行任务的任务数:3,已经执行完的任务数:0

线程池中的线程数:5,队列中等待执行任务的任务数:4,已经执行完的任务数:0

线程池中的线程数:6,队列中等待执行任务的任务数:4,已经执行完的任务数:0

任务10开始执行

线程池中的线程数:7,队列中等待执行任务的任务数:4,已经执行完的任务数:0

任务11开始执行

Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.zyq.mythreadpool.MyRunnable5@2f0e140b rejected from java.util.concurrent.ThreadPoolExecutor@7440e464[Running, pool size = 7, active threads = 7, queued tasks = 4, completed tasks = 0]

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.zyq.mythreadpool.ThreadPoolExecutorTest.main(ThreadPoolExecutorTest.java:21)

任务1执行完毕

任务6开始执行

任务4执行完毕

任务3执行完毕

任务2执行完毕

任务5执行完毕

任务9开始执行

任务8开始执行

任务7开始执行

任务10执行完毕

任务11执行完毕

任务6执行完毕

任务9执行完毕

任务8执行完毕

任务7执行完毕

中间报错的原因是,将第12个任务数使用拒绝策略拒绝掉了。

 

posted on   ~码铃薯~  阅读(36)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
历史上的今天:
2020-04-10 postgresql数据库-number类型模糊查询
2020-04-10 在线朗读软件

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示