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

并发容器与线程池

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

并发容器与线程池

一、容器分类
  • Collection是一个个元素的加到容器;
  • Map是一对对元素的加入容器;
  • Queue主要是为高并发提高服务;

物理上只有两种分类:连续存储的数组 + 非连续存储的链表


Vector、HashTable是最早期的容器,每个方法都自带Sychronized,基本不用,只需要了解其数据结构;

Map高并发时使用ConcurrentHashMap主要是因为它读取数据的速度快,插入数据的速度未必会比HashTable、SychronizedHashMap快;
(发展历程:HashTable — HashMap — SynchronizedMap — ConcurrentHashMap)

Collection高并发时用Queue,可以保证线程安全同时效率高,要保证元素的一致性,可以使用Set里的同步Set数据结构;
(发展历程:Vector — List/Set — Queue)

二、Queue

与List的区别主要是添加了许多对多线程友好的api(offer、peek、poll、put、take)

  • BlockingQueue:在queue的接口方法上添加了两个方法put和take在队列满了和空了时会阻塞(add/remove方法会报异常,offer/poll不报异常但会退出程序),底层用LockSupport的park和unpark实现了Condition.await()方法导致阻塞(生产者消费者模型);

  • ArrayBlockingQueue:有界数组式阻塞队列;

  • linkedBlockingQueue:链式阻塞队列;

  • PriorityQueue:小顶堆排序,根据加入的元素的大小从小到大输出,不是按照加入时间的先后输出;

  • DelayQueue:按照加入时设置的定时时间先后输出;

  • SynchronousQueue:一个线程先执行queue.take()并阻塞,当另一个线程执行queue.put()时阻塞线程会拿到该数据并不再阻塞,但是该queue中始终不能存放对象,仅仅作为两个线程传递数据的手段;

  • TransferQueue:多个线程等待其他线程来传输对象,队列可以支持多个线程之间传递数据,而SynchronousQueue只能支持两个线程之间传递数据;

三、线程池
  • Runnable:定义线程执行任务的接口;(接口)
  • Callable = Runnable + return:在Runnable的基础上增加了一个执行完任务后将来会返回的一个结果值;(接口)
  • Future:存放Callable接口中将来返回的结果值;(接口)
  • FutureTask = Future + Runnable:可以执行任务并将任务的返回结果存放在对象自身上;(类)

Callable可以执行一个带返回值的任务,但是他的返回值需要存储在Future中,而FutureTask实现了Runnable和Future,所以他可以执行一个带返回值的任务,并将返回值存在自己的对象中,future执行任务的线程和主线程是异步的,但是主线程从future中获取返回值是同步阻塞的。

public class FutureTaskDemo {
    public static void main(String[] args) {
        FutureTask ft = new FutureTask<>(()->{
            return "future task";
        });
        
        new Thread(ft).start();

        try {
            
            System.out.println(ft.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

线程池分类

  • ThreadPoolExecutor:普通线程池;(一个任务队列)
  • ForkJoinPool:将总任务分解成多片执行然后再汇总;(多个任务队列)
  • WorkStealingPool:每一个线程有自己的一个任务队列,当一个线程任务队列空了后,可以从其他线程的队列中拿任务来执行;

七大参数

  • 核心线程数
  • 最大线程数
  • 线程空闲存活时间(大于核心线程数的线程会被OS回收)
  • 空闲时间单位
  • 任务阻塞队列
  • 线程工厂
  • 拒绝策略:JDK默认提供了四种,但是这是可以自定义的,所以准确的说没有具体上限(实际中都是自定义的处理策略,一般会把没处理的任务丢到消息队列或者数据库,然后用日志记录还有哪些任务没被处理)

默认的线程池

  • SingleThreadExecutor:只有一个线程,保证顺序执行任务;
    为什么不直接new一个线程?——线程池有任务队列,有生命周期管理;

  • CachedThreadPool:核心线程数为0,最大线程数为Integer.MAX_VALUE,线程存活时间为0,任务队列为SynchronousQueue也就是说有一个任务来了必须有一个线程来执行,不能放到队列里;

  • FixedThreadPool:固定线程数量,核心线程和最大线程都是一样的一个固定的值;具体使用多少线程数可以结合压力测试用一个经验公式计算;

  • ScheduledThreadPool:用来执行定时任务的线程池,任务队列使用的是DelayedWorkQueue,加入的任务都带有一个延迟执行的时间,时间到了用一个线程去执行;

note:用线程池应对亿级流量:先将流量分发到多个边缘服务器,每个服务器中存有的并发量仍然很高,用线程池加消息队列解决。

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

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

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