(2)线程池的7种创建方式

线程池创建

主要两种思路:

  1. 通过 ThreadPoolExecutor 创建的线程池;
  2. 通过 Executors 创建的线程池。

创建方式有7种:

  1. Executors.newFixedThreadPool:创建⼀个固定⼤⼩的线程池,可控制并发的线程数,超出的线程会在队列中等待
  2. Executors.newCachedThreadPool:创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,若线程数不够,则新建线程
  3. Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执⾏顺序
  4. Executors.newScheduledThreadPool:创建⼀个可以执⾏延迟任务的线程池
  5. Executors.newSingleThreadScheduledExecutor:创建⼀个单线程的可以执⾏延迟任务的线程池
  6. Executors.newWorkStealingPool:创建⼀个抢占式执⾏的线程池(任务执⾏顺序不确定)【JDK1.8 添加】
  7. ThreadPoolExecutor:最原始的创建线程池的⽅式,它包含了 7 个参数可供设置,后⾯会详细讲

1.固定数量的线程池

public class TreadPoolDemo3{
  public static void main(String[] args){
     ExecutorService threadPool = Exectors.newFixedThreadPool(2);
     //添加任务方式 1
        threadPool.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });

     //添加任务方式2
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
  }
}


输出:
pool-1-thread-1
pool-1-thread-2

a.线程池返回结果

public class ThreadPoolDemo4 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService threadPool =  Executors.newFixedThreadPool(2);
        //执行任务
        Future<Integer> result = threadPool.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int num = new Random().nextInt(10);
                System.out.println("随机数" + num);
                return num;
            }
        });
 
        //打印线程池返回方式
        System.out.println("返回结果:" + result.get());
    }
}
输出
随机数8
返回结果:8

b.⾃定义线程池名称或优先级

public class ThreadPoolDemo5 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
         // 创建线程工厂
        ThreadFactory threadFactory = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                //!!!!!!!一定要注意:要把任务Runnable设置给新创建的线程
                Thread thread = new Thread(r);
                //设置线程的命名规则
                thread.setName("我的线程" + r.hashCode());
                //设置线程的优先级
                thread.setPriority(Thread.MAX_PRIORITY);
                return thread;
            }
        };
        ExecutorService threadPool = Executors.newFixedThreadPool(2,threadFactory);
        //执行任务1
        Future<Integer> result = threadPool.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int num = new Random().nextInt(10);
                System.out.println(Thread.currentThread().getPriority() + ", 随机数:" + num);
                return num;
            }
        });
        //打印线程池返回结果
        System.out.println("返回结果:" + result.get());
    }
}

2.带缓存的线程池

public class ThreadPoolDemo6 {
    public static void main(String[] args) {
        //创建线程池
        ExecutorService service = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            service.submit(() -> {
                System.out.println("i : " + finalI + "|线程名称:" + Thread.currentThread().getName());
            });
        }
    }
}
输出
i : 1|线程名称:pool-1-thread-2
i : 4|线程名称:pool-1-thread-5
i : 3|线程名称:pool-1-thread-4
i : 5|线程名称:pool-1-thread-6
i : 0|线程名称:pool-1-thread-1
i : 2|线程名称:pool-1-thread-3
i : 6|线程名称:pool-1-thread-7
i : 7|线程名称:pool-1-thread-8
i : 8|线程名称:pool-1-thread-9
i : 9|线程名称:pool-1-thread-1

优点:线程池会根据任务数量创建线程池,并且在一定时间内可以重复使用这些线程,产生相应的线程池。

缺点:适用于短时间有大量任务的场景,它的缺点是可能会占用很多的资源。

3.执⾏定时任务

a.延迟执⾏(⼀次)

public class ThreadPoolDemo7 {
    public static void main(String[] args) {
        //创建线程池
        ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
        System.out.println("添加任务的时间:" + LocalDateTime.now());
        //执行定时任务(延迟3s执行)只执行一次
        service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行子任务:" + LocalDateTime.now());
            }
        },3, TimeUnit.SECONDS);
    }
}
输出
添加任务的时间:2022-04-13T14:19:39.983
执行子任务:2022-04-13T14:19:42.987

b. 固定频率执⾏

public class ThreadPoolDemo8 {
    public static void main(String[] args) {
        //创建线程池
        ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
        System.out.println("添加任务时间:" + LocalDateTime.now());
        //2s之后开始执行定时任务,定时任务每隔4s执行一次
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行任务:" + LocalDateTime.now());
            }
        },2,4, TimeUnit.SECONDS);
    }
}
输出
添加任务时间:2022-04-13T14:24:38.810
执行任务:2022-04-13T14:24:40.814
执行任务:2022-04-13T14:24:44.814
执行任务:2022-04-13T14:24:48.813
执行任务:2022-04-13T14:24:52.815
执行任务:2022-04-13T14:24:56.813
执行任务:2022-04-13T14:25:00.813
执行任务:2022-04-13T14:25:04.814
执行任务:2022-04-13T14:25:08.813
... ...
... ...
执行任务:2022-04-13T14:26:44.814
执行任务:2022-04-13T14:26:48.813```

注意事项:

public class ThreadPoolDemo9 {
   public static void main(String[] args) {
       //创建线程池
       ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
       System.out.println("添加任务时间:" + LocalDateTime.now());
       service.scheduleAtFixedRate(new Runnable() {
           @Override
           public void run() {
               System.out.println("执行任务: " + LocalDateTime.now());
               try {
                   Thread.sleep(5 * 1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       },2,4, TimeUnit.SECONDS);
   }
}
输出
添加任务时间:2022-04-13T14:33:34.551
执行任务: 2022-04-13T14:33:36.556
执行任务: 2022-04-13T14:33:41.557
执行任务: 2022-04-13T14:33:46.559
执行任务: 2022-04-13T14:33:51.561
执行任务: 2022-04-13T14:33:56.562
执行任务: 2022-04-13T14:34:01.564
执行任务: 2022-04-13T14:34:06.566
执行任务: 2022-04-13T14:34:11.566
执行任务: 2022-04-13T14:34:16.567
执行任务: 2022-04-13T14:34:21.570
执行任务: 2022-04-13T14:34:26.570
... ....

(2)线程池的7种创建方式_第1张图片
c.scheduleAtFixedRate VS scheduleWithFixedDelay
scheduleAtFixedRate 是以上⼀次任务的开始时间,作为下次定时任务的参考时间的(参考时间+延迟任务=任务执⾏)。scheduleWithFixedDelay 是以上⼀次任务的结束时间,作为下次定时任务的参考时间的。

public class ThreadPoolDemo10 {
    public static void main(String[] args) {
        //创建线程池
        ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
        System.out.println("添加任务时间:" + LocalDateTime.now());
        //2s之后开始执行定时任务,定时任务每隔4s执行一次
        service.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行任务:" + LocalDateTime.now());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, 2, 4, TimeUnit.SECONDS);
    }
}
输出
添加任务时间:2022-04-13T14:46:02.871
执行任务:2022-04-13T14:46:04.876
执行任务:2022-04-13T14:46:09.878
执行任务:2022-04-13T14:46:14.880
执行任务:2022-04-13T14:46:19.883
执行任务:2022-04-13T14:46:24.885
执行任务:2022-04-13T14:46:29.888
执行任务:2022-04-13T14:46:34.888
执行任务:2022-04-13T14:46:39.891
执行任务:2022-04-13T14:46:44.893
执行任务:2022-04-13T14:46:49.895
执行任务:2022-04-13T14:46:54.897
执行任务:2022-04-13T14:46:59.900
执行任务:2022-04-13T14:47:04.901
... ...

4.定时任务单线程

public class ThreadPoolDemo11 {
    public static void main(String[] args) {
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        System.out.println("添加任务的时间:" + LocalDateTime.now());
        service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行时间:" + LocalDateTime.now());
            }
        },2, TimeUnit.SECONDS );
    }
}
输出
添加任务的时间:2022-04-13T15:06:38.100
执行时间:2022-04-13T15:06:40.106

5. 单线程线程池

public class ThreadPoolDemo12 {
    public static void main(String[] args) {
        ExecutorService service = Executors.newSingleThreadScheduledExecutor();
        for (int i = 0; i < 10; i++) {
            service.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程名:" + Thread.currentThread().getName());
                }
            });
        }
    }
}
输出
线程名:pool-1-thread-1
线程名:pool-1-thread-1
线程名:pool-1-thread-1
线程名:pool-1-thread-1
线程名:pool-1-thread-1
线程名:pool-1-thread-1
线程名:pool-1-thread-1
线程名:pool-1-thread-1
线程名:pool-1-thread-1
线程名:pool-1-thread-1
  • 复用线程。
  • 单线程的线程池提供了任务队列和拒绝策略(当任务队列满了之后(Integer.MAX_VALUE),新来的任务就会拒绝策略)

6.根据当前CPU⽣成线程池

public class ThreadPoolDemo13 {
    public static void main(String[] args) {
        ExecutorService service = Executors.newWorkStealingPool();
        for (int i = 0; i < 10; i++) {
            service.submit(() -> {
                System.out.println("线程名" + Thread.currentThread().getName());
            });
            
            while(!service.isTerminated()) {
            }
        }
    }
}
输出
线程名ForkJoinPool-1-worker-1

7.ThreadPoolExecutor

(2)线程池的7种创建方式_第2张图片
参数说明:
(2)线程池的7种创建方式_第3张图片
(2)线程池的7种创建方式_第4张图片

public class ThreadPoolDemo14 {
    public static void main(String[] args) {
        ThreadFactory factory = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                return thread;
            }
        };
        // 手动创建线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 100, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1), new ThreadPoolExecutor.CallerRunsPolicy());
        for (int i = 0; i < 4; i++) {
            int finalI = i;
            executor.submit(() -> {
                System.out.println(Thread.currentThread().getName() + "执行任务:" + finalI);
            });
        }
        //终止线程
        executor.shutdown();
    }
}
输出
main执行任务:2
pool-1-thread-1执行任务:0
main执行任务:3
pool-1-thread-1执行任务:1

你可能感兴趣的:(#,单线程与多线程,java,jvm,开发语言)