Java 并发工具箱之concurrent包

概述

java.util.concurrent 包是专为 Java并发编程而设计的包。包下的所有类可以分为如下几大类:

  • locks部分:显式锁(互斥锁和速写锁)相关;
  • atomic部分:原子变量类相关,是构建非阻塞算法的基础;
  • executor部分:线程池相关;
  • collections部分:并发容器相关;
  • tools部分:同步工具相关,如信号量、闭锁、栅栏等功能;

类图结构:

J.U.C

脑图地址: http://www.xmind.net/m/tJy5,感谢深入浅出 Java Concurrency ,此脑图在这篇基础上修改而来。

BlockingQueue

此接口是一个线程安全存取实例的队列。

使用场景

BlockingQueue通常用于一个线程生产对象,而另外一个线程消费这些对象的场景。

BlockingQueue

注意事项:

  • 此队列是有限的,如果队列到达临界点,Thread1就会阻塞,直到Thread2从队列中拿走一个对象。
  • 若果队列是空的,Thread2会阻塞,直到Thread1把一个对象丢进队列。

相关方法

BlockingQueue中包含了如下操作方法:

Throws ExceptionSpecial ValueBlocksTimes Out
Insertadd(o)offer(o)put(o)offer(o, timeout, timeunit)
Removeremove(o)poll()take()poll(timeout, timeunit)
Examineelement()peek()

名词解释:

  • Throws Exception: 如果试图的操作无法立即执行,抛一个异常。
  • Special Value: 如果试图的操作无法立即执行,返回一个特定的值(常常是 true / false)。
  • Blocks: 如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行。
  • Times Out: 如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。返回一个特定值以告知该操作是否成功(典型的是 true / false)。

注意事项:

  • 无法插入 null,否则会抛出一个 NullPointerException。
  • 队列这种数据结构,导致除了获取开始和结尾位置的其他对象的效率都不高,虽然可通过remove(o)来移除任一对象。

实现类

因为是一个接口,所以我们必须使用一个实现类来使用它,有如下实现类:

  • ArrayBlockingQueue: 数组阻塞队列
  • DelayQueue: 延迟队列
  • LinkedBlockingQueue: 链阻塞队列
  • PriorityBlockingQueue: 具有优先级的阻塞队列
  • SynchronousQueue: 同步队列

使用示例:

见: BlockingQueue

ArrayBlockingQueue

ArrayBlockingQueue 是一个有界的阻塞队列

  • 内部实现是将对象放到一个数组里。数组有个特性:一旦初始化,大小就无法修改。因此无法修改ArrayBlockingQueue初始化时的上限。
  • ArrayBlockingQueue 内部以 FIFO(先进先出)的顺序对元素进行存储。队列中的头元素在所有元素之中是放入时间最久的那个,而尾元素则是最短的那个。

DelayQueue

DelayQueue 对元素进行持有直到一个特定的延迟到期。注入其中的元素必须实现 java.util.concurrent.Delayed 接口:

public interface Delayed extends Comparable<Delayed< {  public long getDelay(TimeUnit timeUnit);  // 返回将要延迟的时间段
}
  • 1
  • 2
  • 3
  • 在每个元素的 getDelay() 方法返回的值的时间段之后才释放掉该元素。如果返回的是 0 或者负值,延迟将被认为过期,该元素将会在 DelayQueue 的下一次 take 被调用的时候被释放掉。
  • Delayed 接口也继承了 java.lang.Comparable 接口,Delayed对象之间可以进行对比。这对DelayQueue 队列中的元素进行排序时有用,因此它们可以根据过期时间进行有序释放。

LinkedBlockingQueue

内部以一个链式结构(链接节点)对其元素进行存储 。

  • 可以选择一个上限。如果没有定义上限,将使用 Integer.MAX_VALUE 作为上限。
  • 内部以 FIFO(先进先出)的顺序对元素进行存储。

PriorityBlockingQueue

一个无界的并发队列,它使用了和类 java.util.PriorityQueue 一样的排序规则。

  • 无法向这个队列中插入 null 值。
  • 插入到 其中的元素必须实现 java.lang.Comparable 接口。
  • 对于具有相等优先级(compare() == 0)的元素并不强制任何特定行为。
  • 从一个 PriorityBlockingQueue 获得一个 Iterator 的话,该 Iterator 并不能保证它对元素的遍历是以优先级为序的。

SynchronousQueue

一个特殊的队列,它的内部同时只能够容纳单个元素。

  • 如果该队列已有一元素的话,试图向队列中插入一个新元素的线程将会阻塞,直到另一个线程将该元素从队列中抽走。
  • 如果该队列为空,试图向队列中抽取一个元素的线程将会阻塞,直到另一个线程向队列中插入了一条新的元素。

BlockingDeque

此接口表示一个线程安全放入和提取实例的双端队列

使用场景

通常用在一个线程既是生产者又是消费者的时候。
BlockingDeque

注意事项

  • 如果双端队列已满,插入线程将被阻塞,直到一个移除线程从该队列中移出了一个元素。
  • 如果双端队列为空,移除线程将被阻塞,直到一个插入线程向该队列插入了一个新元素。

相关方法

Throws ExceptionSpecial ValueBlocksTimes Out
InsertaddFirst(o)offerFirst(o)putFirst(o)offerFirst(o, timeout, timeunit)
RemoveremoveFirst(o)pollFirst(o)takeFirst(o)pollFirst(timeout, timeunit)
ExaminegetFirst(o)peekFirst(o)
Throws ExceptionSpecial ValueBlocksTimes Out
InsertaddLast(o)offerLast(o)putLast(o)offerLast(o, timeout, timeunit)
RemoveremoveLast(o)pollLast(o)takeLast(o)pollLast(timeout, timeunit)
ExaminegetLast(o)peekLast(o)

注意事项

  • 关于方法的处理方式和上节一样。
  • BlockingDeque 接口继承自 BlockingQueue 接口,可以用其中定义的方法。

实现类

  • LinkedBlockingDeque : 链阻塞双端队列

LinkedBlockingDeque

LinkedBlockingDeque 是一个双端队列,可以从任意一端插入或者抽取元素的队列。

  • 在它为空的时候,一个试图从中抽取数据的线程将会阻塞,无论该线程是试图从哪一端抽取数据。

ConcurrentMap

一个能够对别人的访问(插入和提取)进行并发处理的 java.util.Map接口。
ConcurrentMap 除了从其父接口 java.util.Map 继承来的方法之外还有一些额外的原子性方法。

实现类

因为是接口,必须用实现类来使用它,其实现类为

  • ConcurrentHashMap

ConcurrentHashMap与HashTable比较

  • 更好的并发性能,在你从中读取对象的时候 ConcurrentHashMap 并不会把整个 Map 锁住,只是把 Map 中正在被写入的部分进行锁定。
  • 在被遍历的时候,即使是 ConcurrentHashMap 被改动,它也不会抛 ConcurrentModificationException。

ConcurrentNavigableMap

一个支持并发访问的 java.util.NavigableMap,它还能让它的子 map 具备并发访问的能力。

headMap

headMap(T toKey) 方法返回一个包含了小于给定 toKey 的 key 的子 map。

tailMap

tailMap(T fromKey) 方法返回一个包含了不小于给定 fromKey 的 key 的子 map。

subMap

subMap() 方法返回原始 map 中,键介于 from(包含) 和 to (不包含) 之间的子 map。

更多方法

  • descendingKeySet()
  • descendingMap()
  • navigableKeySet()

CountDownLatch

CountDownLatch 是一个并发构造,它允许一个或多个线程等待一系列指定操作的完成。

  • CountDownLatch 以一个给定的数量初始化。countDown() 每被调用一次,这一数量就减一。
  • 通过调用 await() 方法之一,线程可以阻塞等待这一数量到达零。

CyclicBarrier

CyclicBarrier 类是一种同步机制,它能够对处理一些算法的线程实现同步。

更多实例参考: CyclicBarrier

Exchanger

Exchanger 类表示一种两个线程可以进行互相交换对象的会和点。

更多实例参考: Exchanger

Semaphore

Semaphore 类是一个计数信号量。具备两个主要方法:

  • acquire()
  • release()
  • 每调用一次 acquire(),一个许可会被调用线程取走。
  • 每调用一次 release(),一个许可会被返还给信号量。

Semaphore 用法

  • 保护一个重要(代码)部分防止一次超过 N 个线程进入。
  • 在两个线程之间发送信号。

保护重要部分

如果你将信号量用于保护一个重要部分,试图进入这一部分的代码通常会首先尝试获得一个许可,然后才能进入重要部分(代码块),执行完之后,再把许可释放掉。

Semaphore semaphore = new Semaphore(1);  
//critical section  
semaphore.acquire();  
...  
semaphore.release();
  • 1
  • 2
  • 3
  • 4
  • 5

在线程之间发送信号

如果你将一个信号量用于在两个线程之间传送信号,通常你应该用一个线程调用 acquire() 方法,而另一个线程调用 release() 方法。

  • 如果没有可用的许可,acquire() 调用将会阻塞,直到一个许可被另一个线程释放出来。
  • 如果无法往信号量释放更多许可时,一个 release() 调用也会阻塞。

公平性

无法担保掉第一个调用 acquire() 的线程会是第一个获得一个许可的线程。

可以通过如下来强制公平:

Semaphore semaphore = new Semaphore(1, true); 
  • 1
  • 需要注意,强制公平会影响到并发性能,建议不使用。

ExecutorService

这里之前有过简单的总结: Java 中几种常用的线程池

存在于 java.util.concurrent 包里的 ExecutorService 实现就是一个线程池实现。

实现类

此接口实现类包括:

  • ScheduledThreadPoolExecutor : 通过 Executors.newScheduledThreadPool(10)创建的
  • ThreadPoolExecutor: 除了第一种的其他三种方式创建的

相关方法

  • execute(Runnable):
    无法得知被执行的 Runnable 的执行结果
  • submit(Runnable):
    返回一个 Future 对象,可以知道Runnable 是否执行完毕。
  • submit(Callable):
    Callable 实例除了它的 call() 方法能够返回一个结果,通过Future可以获取。
  • invokeAny(…):
    传入一系列的 Callable 或者其子接口的实例对象,无法保证返回的是哪个 Callable 的结果 ,只能表明其中一个已执行结束。
    如果其中一个任务执行结束(或者抛了一个异常),其他 Callable 将被取消。
  • invokeAll(…):
    返回一系列的 Future 对象,通过它们你可以获取每个 Callable 的执行结果。

关闭ExecutorService

  • shutdown() : 不会立即关闭,但它将不再接受新的任务
  • shutdownNow(): 立即关闭

ThreadPoolExecutor

  • ThreadPoolExecutor 使用其内部池中的线程执行给定任务(Callable 或者 Runnable)。

ScheduledExecutorService(接口,其实现类为ScheduledThreadPoolExecutor)

  • ScheduledExecutorService能够将任务延后执行,或者间隔固定时间多次执行。
  • ScheduledExecutorService中的 任务由一个工作者线程异步执行,而不是由提交任务给 ScheduledExecutorService 的那个线程执行。

相关方法

  • schedule (Callable task, long delay, TimeUnit timeunit):
    Callable 在给定的延迟之后执行,并返回结果。
  • schedule (Runnable task, long delay, TimeUnit timeunit)
    除了 Runnable 无法返回一个结果之外,和第一个方法类似。
  • scheduleAtFixedRate (Runnable, long initialDelay, long period, TimeUnit timeunit)
    这一方法规划一个任务将被定期执行。该任务将会在首个 initialDelay 之后得到执行,然后每个 period 时间之后重复执行。
    period 被解释为前一个执行的开始和下一个执行的开始之间的间隔时间。
  • scheduleWithFixedDelay (Runnable, long initialDelay, long period, TimeUnit timeunit)
    和上一个方法类似,只是period 则被解释为前一个执行的结束和下一个执行的结束之间的间隔。

ForkJoinPool

ForkJoinPool 在 Java 7 中被引入。它和 ExecutorService 很相似,除了一点不同。ForkJoinPool 让我们可以很方便地把任务分裂成几个更小的任务,这些分裂出来的任务也将会提交给 ForkJoinPool。

用法参考:Java Fork and Join using ForkJoinPool

Lock

Lock 是一个类似于 synchronized 块的线程同步机制。但是 Lock 比 synchronized 块更加灵活、精细。

实现类

Lock是一个接口,其实现类包括:

  • ReentrantLock

示例

Lock lock = new ReentrantLock();  
lock.lock();  
//critical section  
lock.unlock();
  • 1
  • 2
  • 3
  • 4
  • 调用lock() 方法之后,这个 lock 实例就被锁住啦。
  • 当lock示例被锁后,任何其他再过来调用 lock() 方法的线程将会被阻塞住,直到调用了unlock() 方法。
  • unlock() 被调用了,lock 对象解锁了,其他线程可以对它进行锁定了。

Lock 和 synchronized区别

  • synchronized 代码块不能够保证进入访问等待的线程的先后顺序。
  • 你不能够传递任何参数给一个 synchronized 代码块的入口。因此,对于 synchronized 代码块的访问等待设置超时时间是不可能的事情。
  • synchronized 块必须被完整地包含在单个方法里。而一个 Lock 对象可以把它的 lock() 和 unlock() 方法的调用放在不同的方法里。

ReadWriteLock

读写锁一种先进的线程锁机制。

  • 允许多个线程在同一时间对某特定资源进行读取,
  • 但同一时间内只能有一个线程对其进行写入。

实现类

  • ReentrantReadWriteLock

规则

  • 如果没有任何写操作锁定,那么可以有多个读操作锁定该锁
  • 如果没有任何读操作或者写操作,只能有一个写线程对该锁进行锁定。

示例:

ReadWriteLock readWriteLock = new ReentrantReadWriteLock();  
readWriteLock.readLock().lock();  // multiple readers can enter this section  // if not locked for writing, and not writers waiting  // to lock for writing.  
readWriteLock.readLock().unlock();  
readWriteLock.writeLock().lock();  // only one writer can enter this section,  // and only if no threads are currently reading.  
readWriteLock.writeLock().unlock();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

更多原子性包装类

位于 atomic包下,包含一系列原子性变量。

  • AtomicBoolean
  • AtomicInteger
  • AtomicLong
  • AtomicReference

参考资料: Java 并发工具包 java.util.concurrent 用户指南
java.util.concurrency - Java Concurrency Utilities

扩展阅读:
深入浅出 Java Concurrency : 讲解的很详细

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/278226.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何提高gps精度_如何在锻炼应用程序中提高GPS跟踪精度

如何提高gps精度l i g h t p o e t/Shutterstocklightpoet /快门Tracking your runs, bike rides, and other workouts is fun because you can see how much you’re improving (or, in my case, dismally failing to improve). For it to be effective, though, you have to …

centos proftp_在CentOS上禁用ProFTP

centos proftpI realize this is probably only relevant to about 3 of the readers, but I’m posting this so I don’t forget how to do it myself! In my efforts to ban the completely insecure FTP protocol from my life entirely, I’ve decided to disable the FTP…

Java通过Executors提供四种线程池

http://cuisuqiang.iteye.com/blog/2019372 Java通过Executors提供四种线程池&#xff0c;分别为&#xff1a;newCachedThreadPool创建一个可缓存线程池&#xff0c;如果线程池长度超过处理需要&#xff0c;可灵活回收空闲线程&#xff0c;若无可回收&#xff0c;则新建线程。n…

MySQL数据库基础(五)——SQL查询

MySQL数据库基础&#xff08;五&#xff09;——SQL查询 一、单表查询 1、查询所有字段 在SELECT语句中使用星号“”通配符查询所有字段在SELECT语句中指定所有字段select from TStudent; 2、查询指定字段 查询多个字段select Sname,sex,email from TStudent; 3、查询指定记录…

基于ZXing Android实现生成二维码图片和相机扫描二维码图片即时解码的功能

NextQRCode ZXing开源库的精简版 **基于ZXing Android实现生成二维码图片和相机扫描二维码图片即时解码的功能原文博客 附源码下载地址** 与原ZXingMini项目对比 NextQRCode做了重大架构修改&#xff0c;原ZXingMini项目与当前NextQRCode不兼容 dependencies {compile com.gith…

如何在Windows 7或Vista上安装IIS

If you are a developer using ASP.NET, one of the first things you’ll want to install on Windows 7 or Vista is IIS (internet information server). Keep in mind that your version of Windows may not come with IIS. I’m using Windows 7 Ultimate edition. 如果您…

ThinkPHP3.2 实现阿里云OSS上传文件

为什么80%的码农都做不了架构师&#xff1f;>>> 0、配置文件Config&#xff0c;加入OSS配置选项&#xff0c;设置php.ini最大上传大小&#xff08;自行解决&#xff0c;这里不做演示&#xff09; OSS > array(ACCESS_KEY_ID > **************, //从OSS获得的…

ipad和iphone切图_如何在iPhone,iPad和Mac上签名PDF

ipad和iphone切图Khamosh PathakKhamosh PathakDo you have documents to sign? You don’t need to worry about printing, scanning, or even downloading a third-party app. You can sign PDFs right on your iPhone, iPad, and Mac. 你有文件要签名吗&#xff1f; 您无需…

在Ubuntu服务器上打开第二个控制台会话

Ubuntu Server has the native ability to run multiple console sessions from the server console prompt. If you are working on the actual console and are waiting for a long running command to finish, there’s no reason why you have to sit and wait… you can j…

Cloudstack系统配置(三)

系统配置 CloudStack提供一个基于web的UI&#xff0c;管理员和终端用户能够使用这个界面。用户界面版本依赖于登陆时使用的凭证不同而不同。用户界面是适用于大多数流行的浏览器包括IE7,IE8,IE9,Firefox Chrome等。URL是:(用你自己的管理控制服务器IP地址代替) 1http://<ma…

如何在Chrome工具栏中固定和取消固定扩展程序

Not all extensions are made equal. Some extensions, like Grammarly, work quietly in the background and don’t need an icon in the Chrome toolbar. Here’s how to pin and unpin extensions for a cleaner Chrome toolbar. 并非所有扩展名都相等。 某些扩展程序(例如…

vim编辑器快捷操作

1、查找 进入编辑器 按下 / 进行查找&#xff0c;回跳到第一个匹配的值&#xff0c;按下n查找下一个 N返回查看上一个 也可根据正则进行查找 2、替换 &#xff1a;s/a/b/g 当前行替换 &#xff1a;%s/a/b/g 全文替换 &#xff1a;5,10s/a/b/g 区域替换: .,2s/foo/bar/g 当…

react-navigation 跨 tabs 返回首页

2019独角兽企业重金招聘Python工程师标准>>> react-navigation 跨 tabs 返回首页 import { NavigationActions } from react-navigation;const navigationAction NavigationActions.reset({ index: 0,actions: [ NavigationActions.navigate({ routeName: RootTab…

ubuntu 默认命令行_从命令行在Ubuntu上设置默认浏览器

ubuntu 默认命令行Ubuntu Linux has a default browser functionality that will automatically launch the correct browser when clicking on a link in a gnome gui application. It’s easy enough to set the default browser using the GUI tools, but sometimes it’s e…

ThreadLocal就是这么简单

前言 今天要研究的是ThreadLocal&#xff0c;这个我在一年前学习JavaWeb基础的时候接触过一次&#xff0c;当时在baidu搜出来的第一篇博文ThreadLocal&#xff0c;在评论下很多开发者认为那博主理解错误&#xff0c;给出了很多有关的链接来指正(可原博主可能没上博客了&#xf…

如何在Twitch上设置捐款

Many people on Twitch stream as a hobby. If you’re thinking about going full-time, though, you’ll need to raise some cash. Setting up donations on Twitch is one way you can do it! Twitch上的许多人都将其作为爱好。 但是&#xff0c;如果您打算全职工作&#x…

JAVA-Concurrency之CountDownLatch说明

2019独角兽企业重金招聘Python工程师标准>>> As per java docs, CountDownLatch is a synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes. CountDownLatch concept is very comm…

设置微软应用商店的代理_如何设置和使用Microsoft家庭安全应用

设置微软应用商店的代理The Microsoft Family Safety app provides a set of reporting and parental control tools for people with Microsoft accounts. With filtering controls, location reporting, and app-usage recording, this app gives parents a way to monitor t…

Linux跨平台远程控制

转载于:https://blog.51cto.com/13660858/2094987

Zoom Host可以真正看到您的所有私人消息吗?

Girts Ragelis/Shutterstock.comGirts Ragelis / Shutterstock.comViral social media posts are alleging that Zoom’s private messages aren’t really private—if you’re chatting privately during a Zoom meeting, the host can see your entire conversation. Is tha…