IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 线程池原理 -> 正文阅读

[Java知识库]线程池原理

线程的等待和通知

? ? ? ? Object类中的方法

wait()让当前线程进入等待状态,直到被通知为止
wait(long)让当前线程进入等待状态,同时设置时间,一直到被通知为止或者时间结束
notify()随机通知一个等待线程(随机无顺序)
notifyAll()通知所有的等待线程

????????需要注意的点:等待和通知方法必须是锁对象,否则会抛出IllegalMonitorStateException

? ? ? ? ?例子:通过锁对象将线程等待,经过5秒通知该线程来执行

/**
 * 通过锁对象将线程等待,经过5秒通知该线程来执行
 */
public class WaitDemo {

    public synchronized void print() throws InterruptedException {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "--->" +i);
            if(i == 50){
                //让当前线程等待
                this.wait();
            }
        }
    }

    public synchronized void notifyTest(){
        //让等待的线程执行
        this.notifyAll();
    }

    public static void main(String[] args) {
        WaitDemo waitDemo = new WaitDemo();
        new Thread(()->{
            try {
                waitDemo.print();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        waitDemo.notifyTest();
    }
}

wait()和sleep()的区别?

调用对象不同锁使用不同唤醒机制不同
wait()由锁对象调用执行wait后 自动释放锁执行wait后,可以被唤醒通知
sleep()由线程调用执行sleep后 不会释放锁执行sleep后,只能等待时间结束后,自动唤醒

生产者消费者模式 (一种设计模式,不属于GOF23)

? ? ? ? 生产者和消费者:

? ? ? ? ? ? ? ? 生产者:某些程序、进程、线程负责生产数据就属于生产者

? ? ? ? ? ? ? ? 消费者:某些程序、进程、线程负责使用数据就属于消费者

? ? ? ? 生产者和消费者之间的问题:

? ? ? ? ? ? ? ? 1.耦合性高,生产者和消费者联系紧密,不利于系统的维护和拓展

? ? ? ? ? ? ? ? 2.并发性低,同时能处理的请求量少

? ? ? ? ? ? ? ? 3.忙闲不均,生产者和消费者的速度不一致,带来系统资源的浪费

? ? ? ? 实现的过程:(就像包子铺,生产者把包子放入笼屉中,消费者不必与生产者密切联系,而是通过第三者进行操作)

? ? ? ? ? ? ? ? 1.通过添加缓冲区,设置上限

? ? ? ? ? ? ? ? 2.生产者生产出数据,放入缓存区,如果满了 则生产者进入等待,直到缓冲区有空的位置通知生产者生产;

? ? ? ? ? ? ? ? 3.消费者从缓冲区取数据进行消费,如果空了,消费者进入等待,直到缓冲区有数据再通知消费者消费。

? ? ? ? 解决问题:

? ? ? ? ? ? ? ? 1.解耦

? ? ? ? ? ? ? ? 2.提高并发性能

? ? ? ? ? ? ? ? 3.解决,忙闲不均

包子铺例子:

/**
 * 包子铺
 */
public class BaoziShop {
    /**
     * 包子
     */
    class Baozi{
        private int id;
        public Baozi(int id) {
            this.id = id;
        }

        @Override
        public String toString() {
            return "包子--" + id;
        }
    }
    //上限
    public static final int MAX_COUNT = 100;
    //缓冲区 存放数据
    private List<Baozi> baozis = new ArrayList<>();

    /**
     * 做包子
     */
    public synchronized void makeBaozi() throws InterruptedException {
        //判断缓冲区是否满了
        if(baozis.size() == MAX_COUNT){
            System.out.printf("缓冲区满了,%s等待%n",Thread.currentThread().getName());
            //让生产者线程等待
            this.wait();
        }else{
            //通知生产者线程生产
            this.notifyAll();
        }
        //创建包子
        Baozi baozi = new Baozi(baozis.size() + 1);
        System.out.println(Thread.currentThread().getName()+"做了"+baozi);
        //保存到缓冲区
        baozis.add(baozi);
    }

    /**
     * 拿包子
     */
    public synchronized void takeBaozi() throws InterruptedException {
        //判断缓冲区是否空了
        if(baozis.size() == 0){
            System.out.printf("缓冲区空了,%s等待%n", Thread.currentThread().getName());
            //让消费者等待
            this.wait();
        }else{
            //通知消费者消费
            this.notifyAll();
        }
        //获得第一个包子,并删除
        if(baozis.size() > 0){
            Baozi baozi = baozis.remove(0);
            System.out.println(Thread.currentThread().getName()+"吃了"+baozi);
        }
    }

    public static void main(String[] args) {
        BaoziShop baoziShop = new BaoziShop();
        //一个生产者
        Thread productor = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                try {
                    baoziShop.makeBaozi();
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        productor.start();
        //10个消费者吃10个包子
        for (int i = 0; i < 10; i++) {
            Thread consumer = new Thread(() ->{
                try {
                    for (int j = 0; j < 10; j++) {
                        baoziShop.takeBaozi();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            consumer.start();
        }
    }
}

阻塞队列

? ? ? ? 应用了生产者消费者模式的集合,能够根据满或者空的情况,自动对线程执行等待和通知

? ? ? ? ?BlockingQueue接口:

? ? ? ? ? ? ? ? ? ? ? ? put添加数据,达到上限会自动让线程等待

? ? ? ? ? ? ? ? ? ? ? ? take取并删除数据,数据空了会自动让线程等待

? ? ? ? 实现类:

????????????????????????ArrayBlockingQueue 类 数据结构为数组

????????????????????????LinkedBlockingQueue类 链表结构

线程池:

? ? ? ? 作用:

? ? ? ? ? ? ? ? 线程是一种宝贵的系统资源,执行完任务后会死亡,如果有大量任务需要处理,需要频繁的创建和销毁线程,造成系统性能降低。

? ? ? ? ? ? ? ? 线程池会保存一定量的线程,线程执行完任务后,会回到线程池中,等待下一个任务,节省系统资源,提升性能。

线程池的使用: (顶层接口:Executor)

? ? ? ? executor(Runnable)? ?启动线程执行一个任务

ExecutorService(用于创建线程池的工具类 )

? ? ? ? 主要的方法:

方法名说明
newCachedThreadPool()创建长度不限的线程池
newFixedThreadPool(int )创建固定长度的线程池
newSingleThreadExecutor()创建单一个数的线程池
newScheduledThreadPool(int)创建可以调度的线程池

????????

线程池的优化配置

????????线程池的实现类(ThreadPoolExecutor)

????????????????线程池的构造方法参数:

????????????????????????corePoolSize 核心线程数,创建线程池后自带线程,不会进行销毁

????????????????????????maximumPoolSize 最大线程数

????????????????????????keepAliveTime 存活时间,非核心线程能够闲置的时间,超过后被销毁

????????????????????????timeUnit 时间单位

????????????????????????blockingQueue 阻塞队列 存放任务(Runnable)的集合

优化配置

  1. 核心线程数 应该和CPU内核数量相关 CPU内核数 * N (N和任务执行需要时间和并发量相关)

    Runtime.getRuntime().availableProcessors()
  2. 最大线程数可以和核心线程数一样,避免频繁创建和销毁线程

  3. 如果存在非核心线程,设置大一点,避免频繁创建和销毁线程

  4. 阻塞队列使用LinkedBlockingQueue,插入和删除任务效率更高

线程池的实现原理? ? ?

????????1、判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。

????????2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。

????????3、判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

?

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-12-10 10:55:44  更:2021-12-10 10:57:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:04:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码