Javase 基础加强 —— 11 线程池

本系列为笔者学习Javase的课堂笔记,视频资源为B站黑马程序员出品的《黑马程序员Java+AI智能辅助编程全套视频教程,java零基础入门到大牛一套通关》,章节分布参考视频教程,为同样学习Javase系列课程的同学们提供参考。

01 概述

用户每发起一个请求,后台就需要创建一个新线程来处理,下次新任务来了肯定又要创建新线程处理的,创建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,这样会严重影响系统的性能。

那么这时,线程池就是一个可以复用线程的技术。

在这里插入图片描述

02 创建线程池

JDK5.0起提供了代表线程池的接口:ExecutorService / ɪɡˈzekjʊtər /

如何创建线程池对象?

① 使用ExecutorService实现类ThreadPoolExecutor自创建一个线程池对象。

在这里插入图片描述

ExecutorService pool = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

② 使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象。

03 处理 Runnable 任务

ExecutorService的常用方法

在这里插入图片描述

MyRunnable.java

package ExecutorDemo;

public class MyRunnable implements Runnable{
    @Override
    public void run(){
        for(int i=0; i<5; i++){
            System.out.println(Thread.currentThread().getName());
        }
    }
}

ExecutorServiceDemo1.java

package ExecutorDemo;

import java.util.concurrent.*;

public class ExecutorServiceDemo1 {
    public static void main(String[] args) {
        //目标:创建线程池对象
        //1.使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        //2.使用线程池处理Runnable任务
        Runnable target = new MyRunnable();
        pool.execute(target); //提交第1个任务 创建第1个线程 自动启动线程处理这个任务
        pool.execute(target); //提交第1个任务 创建第1个线程 自动启动线程处理这个任务
        pool.execute(target); //提交第1个任务 创建第1个线程 自动启动线程处理这个任务
        pool.execute(target); //复用线程
        pool.execute(target); //复用线程

        //3.关闭线程池
        //pool.shutdown();
    }
}

问:什么时候开始创建临时线程?

新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时会创建临时线程。

问:什么时候会拒绝新任务?

新任务提交时发现核心线程和临时线程都在忙,任务队列也满了,此时会拒绝任务。

在这里插入图片描述

MyRunnable.java

package ExecutorDemo;

public class MyRunnable implements Runnable{

    @Override
    public void run(){
        for(int i=0; i<5; i++){
            System.out.println(Thread.currentThread().getName() + "输出" + i);
            try {
                Thread.sleep(Integer.MAX_VALUE);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

ExecutorServiceDemo1.java

package ExecutorDemo;

import java.util.concurrent.*;

public class ExecutorServiceDemo1 {
    public static void main(String[] args) {
        //目标:创建线程池对象
        //1.使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        //2.使用线程池处理Runnable任务
        Runnable target = new MyRunnable();
        pool.execute(target); //召唤第1个正式工
        pool.execute(target); //召唤第2个正式工
        pool.execute(target); //召唤第3个正式工

        pool.execute(target); //门口等待1位
        pool.execute(target); //门口等待2位
        pool.execute(target); //门口等待3位

        pool.execute(target); //招聘第1个临时工
        pool.execute(target); //招聘第2个临时工
        pool.execute(target); //老板亲自服务

        //3.关闭线程池
        //pool.shutdown();
    }
}

在这里插入图片描述

04 处理 Callable 任务

ExecutorService的常用方法

在这里插入图片描述

MyCallable.java

package ExecutorDemo;

import java.util.concurrent.Callable;

public class MyCallable implements Callable<String> {
    private int n;
    public MyCallable(int n){
        this.n = n;
    }

    @Override
    public String call() throws Exception{
        int sum = 0;
        for(int i=1; i<=n; i++){
            sum += i;
        }

        return Thread.currentThread().getName() + "子线程" + n + "计算sum为:" + sum;
    }
}

ExecutorServiceDemo2.java

package ExecutorDemo;

import java.util.concurrent.*;

public class ExecutorServiceDemo2 {
    public static void main(String[] args) {
        //目标:创建线程池对象
        //1.使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        //2.使用线程池处理Callable任务
        Future<String> f1 = pool.submit(new MyCallable(100));
        Future<String> f2 = pool.submit(new MyCallable(200));
        Future<String> f3 = pool.submit(new MyCallable(300));
        Future<String> f4 = pool.submit(new MyCallable(400));

        try {
            System.out.println(f1.get());
            System.out.println(f2.get());
            System.out.println(f3.get());
            System.out.println(f4.get());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

05 通过 Executors 创建新线程

Executors 是一个线程池的工具类,其提供了很多静态方法用于返回不同特点的线程池对象。

在这里插入图片描述

ExecutorService pool Executors.newFixedThreadPool(3);

在这里插入图片描述

06 并发/并行

当前正在运行的程序为一个独立的进程,而线程是属于进程的,一个进程中可以同时运行很多个线程。

进程中的线程是由CPU负责调度执行的,但CPU能同时处理线程的数量有限,为了保证全部线程都能往前执行,CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们的感觉这些线程在同时执行,这就是并发。

并发是虚假的同时,并行是真正的同时。

07 案例:红包雨游戏

需求:某企业有100名员工,员工的工号依次是1,2,3,4,…,100。现在公司举办了年会活动,活动中有一个红包雨环节,要求共计发出200个红包雨。其中小红包在1-30元之间,总占比为80%,大红包[31-100】元,总占比为20%。

分析:100个员工实际上就是100个线程,来竞争200个红包。

Test.java

package threadDemo;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Test {
    public static void main(String[] args) {
        List<Integer> redPacket = getRedPacket();

        //2.定义线程类,创建100个线程,竞争200个红包
        for(int i=1; i<=100; i++){
            new PeopleGetRedPacket(redPacket, i + "号程序员");
        }
    }

    public static List<Integer> getRedPacket(){
        Random r = new Random();

        //1.创建List集合,准备200个随机红包
        List<Integer> redPacket = new ArrayList<>();
        for(int i=1; i<=160; i++){
            redPacket.add(r.nextInt(30) + 1);
        }
        for(int i=1; i<=40; i++){
            redPacket.add(r.nextInt(70) + 31);
        }
        return redPacket;
    }
}

PeopleGetRedPacket.java

package threadDemo;

import java.util.List;

public class PeopleGetRedPacket extends Thread{
    //构造函数立大功!!!
    private List<Integer> redPacket;
    public PeopleGetRedPacket(List<Integer> redPacket, String name){
        super(name);
        this.redPacket = redPacket;
    }

    @Override
    public void run(){
        //3.创建加锁机制,模拟抢红包过程
        String name = Thread.currentThread().getName();
        while(true){
            if(redPacket.size() == 0){
                break;
            }

            int index = (int)(Math.random() * redPacket.size());
            Integer money = redPacket.remove(index);
            System.out.println(name + "抢到了" + money + "元");
            if(redPacket.size() == 0){
                System.out.println("活动结束!");
                break;
            }

            try{
                Thread.sleep(10);
            }catch (Exception e){
                e.printStackTrace();
            }

        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值