JAVA基础之线程(三)线程池

刚要

  1. 理解线程池基本概念
  2. 理解线程池工作原理
  3. 【掌握】自定义线程池
  4. 【应用】java内置线程池
  5. 【应用】使用java内置线程池完成综合案例

1. 线程池基本概念

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 线程池使用

2.1 java内置线程池

我们想要自定义线程池,必须先了解线程池的工作原理,才能自己定义线程池;通过java中ThreadPoolExecutor的源码来学习:
java.util.ThreadPoolExecutor类 jdk1.5
该类继承了AbstractExecutorService,而AbstractExecutorService实现了Executor这个接口。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. 自定义线程池

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/*
自定义线程池练习:任务类,需要实现Runnable接口;
包含任务编号,每一个任务执行时间设计为 0.2秒
 */
public class MyTask implements Runnable{
    private int id;//任务编号
    //由于run方法是重写接口中的方法,因此id这个属性初始化可以利用构造函数
    public MyTask(int id){
        this.id = id;
    }
    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println("线程"+name+"即将执行任务:"+id);
        //模拟线程执行的时间
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程"+name+"完成了任务:"+id);
    }
}

import java.util.List;

/*
 编写一个线程类,需要继承Thread类;设计一个属性,用于保存线程的名字;
 设计一个集合,用于保存所有的任务;
 */
public class MyWorker extends Thread{
    private String name;//保存线程的名字
    private List<Runnable> tasks;//所有的任务集合
    //利用构造方法给成员变量赋值
    public MyWorker(String name, List<Runnable> tasks){
        super(name);//
        this.tasks = tasks;
    }
    @Override
    public void run(){
        //判断集合中是否有任务,只要有,就一直执行
        while (tasks.size() > 0){
            Runnable r = tasks.remove(0);//取出当前任务
            r.run();
        }
    }
}

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/*
自定义的线程池类;
成员变量:
    1:任务队列  集合 需要控制线程安全问题
    2:当前线程数量
    3:核心线程数
    4:最大线程数
    5:任务队列的长度
成员方法:
    1:提交任务;直接将任务添加到集合中(任务队列),超出就不让加了
    2:执行任务;判断当前线程的数量,决定创建核心线程还是非核心线程(非核心线程 = 最大线程数量-核心线程数量)

 */
public class MyThreadPool {
    //1:任务队列  集合 需要控制线程安全问题
    private List<Runnable> tasks = Collections.synchronizedList(new LinkedList<>());
    // 2:当前线程数量
    private int num;
    //3:核心线程数
    private int corePoolSize;
    //4:最大线程数
    private int maxSize;
    //5:任务队列的长度
    private int workSize;

    @Override
    public String toString() {
        return "MyThreadPool{" +
                "tasks=" + tasks +
                ", num=" + num +
                ", corePoolSize=" + corePoolSize +
                ", maxSize=" + maxSize +
                ", workSize=" + workSize +
                '}';
    }

    public MyThreadPool(int corePoolSize, int maxSize, int workSize) {
        this.corePoolSize = corePoolSize;
        this.maxSize = maxSize;
        this.workSize = workSize;
    }

    // 1. 提交任务
    public void submit(Runnable r){
        // 判断当前集合中任务的数量是否超出了最大任务数量
        if(tasks.size() >= workSize){
            System.out.println("任务:"+r+"被丢弃了");//饱和机制
        }else {
            tasks.add(r);
            execTask(r);//直接将任务传给方法执行
        }
    }
    //专门用于执行任务
    private void execTask(Runnable r) {
        // 判断当前线程池中线程总数量是否超出了最大核心数,在任务队列里面等待
        if(num < corePoolSize){
            //  创建线程
            new MyWorker("核心线程:"+num,tasks).start();
            num ++;//模拟创建了线程
        }else if(num < maxSize){
            new MyWorker("非核心线程:"+num,tasks).start();
            num ++;//模拟创建了线程
        }else {
            System.out.println("任务:"+ r +"被缓存了。。。");
        }
    }

}

/*
测试类:
    1.创建线程池类对象
    2.提交多任务
 */
public class MyTest {
    public static void main(String[] args) {
        //1.创建线程池类对象
        MyThreadPool pool = new MyThreadPool(2,4,20);//2个核心,2个非核心
        // 2.提交多任务
        for(int i = 0;i<10;i++){
            // 3.创建任务对象,并提交给线程池
            MyTask my = new MyTask(i);
            pool.submit(my);
        }
    }
}

4. java内置线程池

4.1 ExecutorService 接口

该接口继承了Executor这个接口
在这里插入图片描述

import java.util.concurrent.*;

/*
    练习异步计算结果
 */
public class FutureDemo {
    public static void main(String[] args) {
        // 1. 获取线程池对象
        ExecutorService es = Executors.newCachedThreadPool();
        // 2. 创建 Callable类型的任务对象
        Future<Integer> f =  es.submit(new MyCall(1,2));
        // 3. 判断任务是否已经完成
        boolean done =  f.isDone();
        System.out.println("第一次判断任务是否完成"+done);
        boolean cancelled =  f.isCancelled();
        System.out.println("第一次判断任务是否取消"+cancelled);
        try {
            Integer integer = f.get();//一直等待任务的执行,直到完成
            System.out.println("任务执行的结果:"+integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        boolean done2 =  f.isDone();
        System.out.println("第二次判断任务是否完成"+done2);
        boolean cancelled2 =  f.isCancelled();
        System.out.println("第二次判断任务是否取消"+cancelled2);


    }
}

class MyCall implements Callable<Integer>{
    private int a;
    private int b;

    public MyCall(int a, int b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public Integer call() throws Exception {
        String name = Thread.currentThread().getName();
        System.out.println(name+"准备开始计算。。。");
        Thread.sleep(2000);//模拟需要2秒钟运算
        System.out.println(name+"准备计算完成");
        return a+b;
    }
}

4.2 Executors工具类

可以从源码中看到Executors这个工具类包含了很多ExecutorService方法
在这里插入图片描述

在这里插入图片描述
案例一:Executors.newCachedThreadPool()
性能最大化,前提是服务器足够给力。

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

/*
    练习 Executors 获取 ExecutorService,然后调用方法,提交任务
*/
public class MyTest01 {
    public static void main(String[] args) {
        // 1:使用工厂类获取线程池对象
       ExecutorService es =  Executors.newCachedThreadPool();
       // 2:提交任务;任务可以是Runnable的对象,也可以是Callable
        //一共 10个任务,创建了10个线程
        for(int i =1;i<=10;i++){
            es.submit(new MyRunnable1(i));
        }
    }
}

/*
任务类:包含任务编号,在任务中,打印是哪一个线程正在执行任务
 */
class MyRunnable1 implements Runnable{
    //利用构造方法给任务编号
    private int id;

    public MyRunnable1(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        System.out.println("线程:"+Thread.currentThread().getName()+":执行了任务====>"+ id);
    }
}

案例二:Executors.newFixedThreadPool(3);
让服务器压力小写,对性能要求不是那么高

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

/*
    练习 Executors 获取 ExecutorService,然后调用方法,提交任务
*/
public class MyTest01 {
    public static void main(String[] args) {
        // 1:使用工厂类获取线程池对象
//       ExecutorService es =  Executors.newCachedThreadPool();
        //线程池里面最多 3个线程
       ExecutorService es =  Executors.newFixedThreadPool(3);
       // 2:提交任务;任务可以是Runnable的对象,也可以是Callable
        //一共 10个任务,创建了10个线程
        for(int i =1;i<=10;i++){
            es.submit(new MyRunnable1(i));
        }
    }
}

/*
任务类:包含任务编号,在任务中,打印是哪一个线程正在执行任务
 */
class MyRunnable1 implements Runnable{
    //利用构造方法给任务编号
    private int id;

    public MyRunnable1(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        System.out.println("线程:"+Thread.currentThread().getName()+":执行了任务====>"+ id);
    }
}

shutdown();
在这里插入图片描述
在这里插入图片描述

ExecutorService的子接口ScheduledExecutorService;用于延迟或定期执行任务

在这里插入图片描述
在这里插入图片描述

5 案例:秒杀商品

在这里插入图片描述

import java.util.concurrent.ThreadPoolExecutor;

/*
任务类:
    包含了商品数量
    客户名称
    买手机的行为
 */
public class MyTask1 implements Runnable{
    //商品的数量
    private static int goods = 10;//保证商品的数量唯一
    //表示客户名称
    private String userName;

    public MyTask1(String userName) {
        this.userName = userName;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(userName+"正在使用"+name+"参与秒杀任务。。。");
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (MyTask1.class){
            if(goods > 0){// 判断商品是否被抢完
                System.out.println(userName+"使用"+name+"秒杀:"+goods--+"号商品成功");

            }else {
                System.out.println(userName+"使用"+name+"秒杀失败啦!");
            }
        }

    }
}

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyTask1Test {
    public static void main(String[] args) {
        //  1.创建线程池对象
        ThreadPoolExecutor pool = new ThreadPoolExecutor(3,5,1, TimeUnit.MINUTES,new LinkedBlockingDeque<>(15));
        // 2. 循环创建任务对象,模拟20个用户
        for(int i = 1;i<=20;i++){
            MyTask1 myTask1 = new MyTask1("客户"+ i);
            pool.submit(myTask1);
        }
        pool.shutdown();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值