栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java线程池

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java线程池

在目前我们常用的springboot项目中。我们一般会将线程池交由spring进行管理:

@EnableAsync
@Component
public class AsyncThreadPool {

    @Bean
    public ThreadPoolTaskExecutor initializeThreadPool() {
        ThreadPoolTaskExecutor  threadPool = new ThreadPoolTaskExecutor ();
        
        threadPool.setCorePoolSize(5);
        
        threadPool.setMaxPoolSize(10);
        
        threadPool.setQueueCapacity(1000);
        
        threadPool.setKeepAliveSeconds(30);
        
        threadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        
        threadPool.initialize();
        return threadPool;
    }

}
        ThreadPoolTaskExecutor executor = threadPool.initializeThreadPool();
        
        Task task = newTask();
        
        executor.execute(task);
        
        class Task implements Runnable{
        @Override
        public void run() {
                
                executor.shutdown();
            }
        }

线程池的工作机制:

如果线程池工作线程数

如果线程池工作线程数>=corePoolSize并且等待队列未满,将task插入等待队列。

如果线程池工作流程数>=corePoolSize并且等待队列已满,且工作线程数

如果线程池工作流程数>=corePoolSize并且等待队列已满,且工作线程数=maximumPoolSize,执行拒绝策略。

构造函数的参数含义如下:

corePoolSize:指定了线程池中的线程数量,它的数量决定了添加的任务是开辟新的线程去执行,还是放到workQueue任务队列中去;

maximumPoolSize:指定了线程池中的最大线程数量,这个参数会根据你使用的workQueue任务队列的类型,决定线程池会开辟的最大线程数量;

keepAliveTime:当线程池中空闲线程数量超过corePoolSize时,多余的线程会在多长时间内被销毁;

unit:keepAliveTime的单位

workQueue:任务队列,被添加到线程池中,但尚未被执行的任务;它一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列几种;

threadFactory:线程工厂,用于创建线程,一般用默认即可;

handler:拒绝策略;当任务太多来不及处理时,如何拒绝任务;

workQueue任务队列

它一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列;

  • ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,按FIFO原则进行排序
  • linkedBlockingQueue:一个基于链表结构的阻塞队列,吞吐量高于ArrayBlockingQueue。静态工厂方法Excutors.newFixedThreadPool()使用了这个队列
  • SynchronousQueue: 一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量高于linkedBlockingQueue,静态工厂方法Excutors.newCachedThreadPool()使用了这个队列
  • PriorityBlockingQueue:一个具有优先级的无限阻塞队列。

Rejected tasks 拒绝任务

AbortPolicy:默认测策略,抛出RejectedExecutionException运行时异常;

CallerRunsPolicy:这提供了一个简单的反馈控制机制,可以减慢提交新任务的速度;

DiscardPolicy:直接丢弃新提交的任务;

DiscardOldestPolicy:如果执行器没有关闭,队列头的任务将会被丢弃,然后执行器重新尝试执行任务(如果失败,则重复这一过程);

我们可以自己定义RejectedExecutionHandler,以适应特殊的容量和队列策略场景中。

线程状态

线程状态从大的方面来说,可归结为:初始状态、可运行状态、不可运行状态和消亡状态,具体可细分为上图所示7个状态,说明如下:

1)线程的实现有两种方式,一是继承Thread类,二是实现Runnable接口,但不管怎样,当我们new了Thread实例后,线程就进入了初始状态;

2)当该对象调用了start()方法,就进入可运行状态;

3)进入可运行状态后,当该对象被操作系统选中,获得CPU时间片就会进入运行状态;

4)进入运行状态后涉及的情况就比较多,大致有如下情形: ﹒

        run()方法或main()方法结束后,线程就进入终止状态;

        当线程调用了自身的sleep()方法或其他线程的join()方法,就会进入阻塞状态(该状态虽停止当前线程,但并不释放所占有的资源)。

        当sleep()结束或join()结束后,该线程进入可运行状态,继续等待OS分配时间片;

        当线程刚进入可运行状态(注意,还没运行),发现将要调用的资源被锁住(synchroniza,lock),将会立即进入锁池状态,等待获取锁标记(这时的锁池里也许已经有了其他线程在等待获取锁标记,这时它们处于队列状态,既先到先得),一旦线程获得锁标记后,就转入可运行状态,等待OS分配 CPU时间片;

        当线程调用wait()方法后会进入等待队列(进入这个状态会释放所占有的所有资源,与阻塞状态不同),进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒(由于notify()只是唤醒一个线程,但我们由于不能确定具体唤醒的是哪一个线程,也许我们需要唤醒的线程不能够被唤醒,因此在实际使用时,一般都用notifyAll()方法,唤醒有所线程),线程被唤醒后会进入锁池,等待获取锁标记。 当线程调用stop方法,即可使线程进入消亡状态,

wait和sleep的区别

1. Thread类的方法:sleep(),yield()

     Object的方法:wait()和notify()、notifyAll()

2. 每个对象都有一个锁来控制同步访问。Synchronized关键字可以和对象的锁交互,来实现线程的同步。 sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。 

3. wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用 。注意:wait()必须放在synchronized block中,否则会在program runtime时扔出“java.lang.IllegalMonitorStateException”异常。

4. sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常

综上可得两者最大的区别:sleep()睡眠时,保持对象锁,仍然占有该锁;而wait()睡眠时,释放对象锁。

run和start区别:

run只是Thread里面的一个普通方法,start是启动线程的方法

实现了Runnable接口的对象并不是线程,它只是任务。Thread对象才是真正的线程创建者。也就是说,任务和线程是分开的,任务放在线程里面才会被执行

sleep() 和 yield()方法

这两个方法都定义在Thread.java中

        sleep()的作用是让当前线程休眠(正在执行的线程主动让出cpu,然后cpu就可以去执行其他任务),即当前线程会从“运行状态”进入到“休眠(阻塞)状态”。sleep()会指定休眠时间,线程休眠的时候会大于或者等于该休眠时间,当时间过后该线程重新被会形式,他会由“阻塞状态”编程“就绪状态”,从而等待cpu的调度执行,注意:sleep方法只是让出了cpu的执行权,并不会释放同步资源锁。

        yield()的作用是让步,它能够让当前线程从“运行状态”进入到“就绪状态”,从而让其他等待线程获取执行权,但是不能保证在当前线程调用yield()之后,其他线程就一定能获得执行权,也有可能是当前线程又回到“运行状态”继续运行,注意:这里我将上面的“具有相同优先级”的线程直接改为了线程,很多资料都写的是让具有相同优先级的线程开始竞争,但其实不是这样的,优先级低的线程在拿到cpu执行权后也是可以执行,只不过优先级高的线程拿到cpu执行权的概率比较大而已,并不是一定能拿到。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/338273.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号