天天看点

线程池和阻塞队列

阻塞队列

add/remove

        如果队列满了,add(T)会抛出异常        

        如果队列为空,remove()会抛出异常

offer/poll

        如果队列满了,offer(T)会返回false

        如果队列为空,poll()会返回null

put/take

        如果队列满了,put(T)会阻塞

        如果队列为空,take()会阻塞

常用的阻塞队列

       LinkedBlockingQueue:链表实现的阻塞队列,可以不指定大小,默认为Integer.MAX_VALUE

       ArrayBlockingQueue:数组实现的阻塞队列,必须指定大小

       SynchronousQueue:不能存放元素的阻塞队列

线程池

线程池参数

        corePoolSize:核心线程数

        maximumPoolSize:最大线程数、规定阻塞队列满了之后,允许创建的最大任务个数

        keepAliveTime:线程空闲时间

        unit:线程空闲时间单位

        workQueue:阻塞队列

        threadFactory:线程工厂,主要是给线程指定name

        handler:拒绝策略,默认是抛出异常

                 AbortPolicy:当任务书大于maximumPoolSize+阻塞队列大小之后,会抛出异常

                 DiscardPolicy:抛弃最近提交的任务

                 DiscardOldestPolicy:抛弃最早提交未执行的任务

                 CallerRunsPolicy:由调用线程自己执行该任务,如果是主线程那么就是main

线程池工作原理

·         提交的任务数小于等于核心线程数,会创建核心线程执行任务

         ·提交的任务数大于核心线程数,超出部分会被加入阻塞队列中

         ·阻塞队列如果满了,判断超出的任务数是否大于最大线程数,如果大于那么走拒绝策略,否则执行。

合理配置线程池

CPU密集型

        有大量计算型的任务,最大线程数不要超过逻辑核心数

IO密集型

        有大量磁盘io,网络通讯,最大线程数一般配置为2*逻辑核心数

线程不安全的原因

         java内存模型中,为了提高效率在线程中引入了工作内存和主存,工作内存是线程私有的,两个线程同时要修改一个变量,刚开始都是从主存中拷贝一份副本,然后在工作内存中修改值,在未来某个时间刷新到主存中,由于两个线程都是在自己内部的工作内存修改变量,所以最终刷新到主存中的数据可能是不正确的,这就是线程不安全的原因。