JAVA 并发-下

六.阻塞队列

  阻塞队列:当试图向队列添加元素而队列已满,或是想从队列移出元素而队列为空的时候。阻塞队列导线程阻塞。

  方法:队列当作线程管理工具使用,用到put和take方法

     试图想满的队列添加或从空的队列移出元素,add、remove和element操作抛出异常

     因为无法知道何时队列空或满,因此一定要用offer,poll和peek方法作为替代

七.线程安全的集合

  线程安全的实现:多线程并发修改一个数据结构时,很容易破坏这个数据结构,线程安全地实现可以替代锁更容易实现,来保护共享数据结构。

7.1 高效的映射、集和队列

  java.util.concurrent包:提供了映射、有序集和队列的高效实现:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet和ConcurrentLinkedQueue

7.2 映射条目的原子更新

  compute:调用compute方法可以提供一个键和一个计算数值的函数。这个函数可以接受键和相关联的值(如果没有值,则为null)。

  merge:这个方法可以非常方便地实现首次增加一个键,有一个参数表示键不存在时使用的初始值。

7.3 对并发散列映射的批操作

  批操作:会遍历映射,处理遍历过程中找到的元素。

  三种操作:

  ·搜索(search)为每个键或值提供一个函数,直到函数生成一个非null的结果,搜索中止,返回这个函数的结果

  ·归约(reduce)组合所有键或值,使用它提供的一个累加函数。

  ·forEach为所有键或提供一个函数

7.4 并发集视图

  假设想得到一个大的线程安全地集而不是映射,即不是ConcurrentHashSet类

  静态newKeySet方法:生成一个Set<K> 

    Set<String> words = ConcurrentHashMap.<String>newKeySet();

7.5 写数组的拷贝

  CopuOnWriteArrayList和CopyOnWriteArraySet是线程安全的集合。

  当构建一个迭代器时,它包含一个对当前数组的引用,如果数组后来被修改了,迭代器任然用旧数组,旧的迭代器拥有一致的(可能过时的)视图,访问它无须任何同步开销。

7.6 并行数组算法

  Arrays类提供了大量并行化操作。

  静态Arrays.parallelSort方法:可以对一个基本类型值或对象的数组排序。

  parallelSetAll方法:用由一个函数计算得到的值填充一个数组。

  parallelPrefix方法:它会用对应一个给定结合操作的前缀的累加结果替换各个数组元素,例如:

  考虑数组 [1,2,3,4,...]和 × 操作。执行Arrays.parallelPrefix(values,(x,y)->x*y)之后,数组将包含 [1, 1× 2, 1× 2× 3, 1× 2× 3× 4,...]

7.7 Callable与Future

  Callable:Runnable封装一个异步运行的任务,可以把它想想成为一个没有参数和返回值的异步方法。Callable与Runnable类似,但是有返回值。

    public interface Callable<V>
    {
        V call() throw Exception;
    }

  类型参数是返回值的类型,如 Callable<Integer> 表示一个返回Integer对象的异步运算。

  Future:保存异步计算的结果。可以启动一个计算,将Future对象交给某个线程,可以忘掉它,Future对象的所有者在结果计算好之后就可以获得它。

 

九. 执行器

  执行器(Executor)类有许多静态工厂方法用来构建线程池。

  线程池的特点:线程池中包含许多准备运行的空闲线程,将Runnable对象交给线程池,就会有一个线程调用run方法。当run方法退出时,线程池也不会死亡,而是在池中准备下一个请求服务。同时线程池具有减少并发线程的作用。

9.1 线程池

  线程池(thread pool):如果程序中创建了大量的生命期很短的线程,应该使用线程池(thread pool)。

  newCachedThreadPool方法构建了一个线程池;newFixedThreadPool方法构建一个具有固定大小线程池;newSingleThreadExecutor是一个退化了大小为1的线程池,由1个线程执行

  ExecutorService接口的ThreadPoolExecutor类:由上面三个方法返回实现

  可用下面方法之一将Runnable对象或Callable对象提交给ExecutourService:

  Future<?> submit(Runnable task)

  Future<T> submit(Runnable task, T result)

  Future<T> submit(Callaable<T> task)

9.2 预定执行(Scheduled Execution)

  预定执行:ScheduledExecutorService接口具有预定执行或重复执行任务而设计的方法。

  预定执行的特点:可以预定Runnable或Callable在初始的延迟之后只运行一次。也可以预定一个Runnable对象周期性地运行

9.3 控制任务组

  控制任务组:使用执行器可以控制一组相关任务。例如,可以在执行器中使用shutdownNow方法取消所有的任务。

  invokeAny方法提交所有对象到一个Callable对象的集合中,并返回某个已经完成了的任务的结果。

9.4 Fork-Join 框架

  一些应用可能对每个处理器内核使用一个线程,来完成计算密集型任务,如图像和视频,fork-join专门用来支持这一类应用。

  fork-join框架使用了智能方法来平衡可用线程的工作负载。每个线程都有一个双端队列(deque)来完成任务。

9.5 可完成Future

  CompletabelFuture类:与事件处理器不同,可完成future可以“组合”(composed).

  可完成future:可以指定你希望做什么,以及希望用什么顺序做这些工作,虽然不会立即发生,但是重要的是代码放在一起。

十. 同步器

  java.util.concurrent包包含了几个能帮助人们管理相合作的线程集的类,如CyclicBarrier类,Phaser类等

10.1 信号量

  一个信号量管理许多的许可证(permit)。为了通过信号量,线程通过调用acquire 请求许可。其他线程可以通过调用relase释放许可。

10.2 倒计时门栓

  (CountDownLatch)倒计时门栓:让一个线程集等待直到计数变为0;倒计时门栓是一次性地,一旦计数为0,就不能再重用了。

10.3 障栅

  障栅(barrier):CyclicBarrier类实现了一个集结点称为障栅。

  障栅的特点:当一个线程完成了它的那部分后,让它运行到障栅处。一旦所以的线程都达到了障栅处,我们就撤销障栅,让线程继续运行。

  障栅是循环的,可以在所有等待线程被释放后重用。

10.4 交换器

  当两个线程在同一个数据缓冲区的两个实例上工作的时候,就可以使用交换器(Exchanger)

10.5 同步队列

  当一个线程调用SynchronousQueue的put方法时,它会阻塞直到另一个线程调用take方法为止,反之亦然,与Exchanger的情况不同,数据仅仅沿一个方向传递。

posted @   Pray386  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示