最近,和不少公司的“大牛”聊了聊,其中很多是关于“并发和多线程”、“系统架构”、“分布式”等方面内容的。
不少问题,感觉自己表达的不够清晰。
这里面就存在一个“典型问题”和“现象”了:能够根据已有经验和学习能力,把遇到的问题都解决,但是并不能很好地表达出来。
生活中的很多事情,都是“相互选择”“相互考察”的双向问题,你站在“甲方”和“乙方”两个立场,判断往往是不同的。
不能改变别人,就努力提高自己,使得自己有更多的选择,抱怨这些“不公”是没啥用处的,除了心里舒服一点。
为了解决这个问题,还是象往常一样,通过一篇篇的文章和代码,总结经验,写点自己的见解。
在解决一个技术问题,看到了JDK API文档中,关于java.util.concurrent并发包的总体介绍,拿来作为“序”还是挺不错的。
java.util.concurrent,在并发编程中很常用的实用工具类,接口有10多个,实现类有20多个。
此包包括了几个小的、已标准化的可扩展框架,以及一些提供有用功能的类,没有这些类,这些功能会很难实现或实现起来冗长乏味。
下面简要描述主要的组件,另请参阅 locks 和 atomic 包。
执行程序
接口。Executor 是一个简单的标准化接口,用于定义类似于线程的自定义子系统,包括线程池、异步 IO 和轻量级任务框架。
根据所使用的具体 Executor 类的不同,可能在新创建的线程中,现有的任务执行线程中,或者调用 execute() 的线程中执行任务,并且可能顺序或并发执行。
ExecutorService 提供了多个完整的异步任务执行框架。ExecutorService 管理任务的排队和安排,并允许受控制的关闭。
ScheduledExecutorService 子接口及相关的接口添加了对延迟的和定期任务执行的支持。
ExecutorService 提供了安排异步执行的方法,可执行由 Callable 表示的任何函数,结果类似于 Runnable。
Future 返回函数的结果,允许确定执行是否完成,并提供取消执行的方法。
RunnableFuture 是拥有 run 方法的 Future,run 方法执行时将设置其结果。
实现。类 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 提供可调的、灵活的线程池。
Executors 类提供大多数 Executor 的常见类型和配置的工厂方法,以及使用它们的几种实用工具方法。
其他基于 Executor 的实用工具包括具体类 FutureTask,它提供 Future 的常见可扩展实现,以及 ExecutorCompletionService,它有助于协调对异步任务组的处理。
队列
java.util.concurrent ConcurrentLinkedQueue 类提供了高效的、可伸缩的、线程安全的非阻塞 FIFO 队列。
java.util.concurrent 中的五个实现都支持扩展的 BlockingQueue 接口,该接口定义了 put 和 take 的阻塞版本:LinkedBlockingQueue、ArrayBlockingQueue、SynchronousQueue、PriorityBlockingQueue 和 DelayQueue。
这些不同的类覆盖了生产者-使用者、消息传递、并行任务执行和相关并发设计的大多数常见使用的上下文。
BlockingDeque 接口扩展 BlockingQueue,以支持 FIFO 和 LIFO(基于堆栈)操作。
LinkedBlockingDeque 类提供一个实现。
计时
TimeUnit 类为指定和控制基于超时的操作提供了多重粒度(包括纳秒级)。
该包中的大多数类除了包含不确定的等待之外,还包含基于超时的操作。
在使用超时的所有情况中,超时指定了在表明已超时前该方法应该等待的最少时间。
在超时发生后,实现会“尽力”检测超时。但是,在检测超时与超时之后再次实际执行线程之间可能要经过不确定的时间。
接受超时期参数的所有方法将小于等于 0 的值视为根本不会等待。要“永远”等待,可以使用 Long.MAX_VALUE 值。
同步器
四个类可协助实现常见的专用同步语句。
Semaphore 是一个经典的并发工具。
CountDownLatch 是一个极其简单但又极其常用的实用工具,用于在保持给定数目的信号、事件或条件前阻塞执行。
CyclicBarrier 是一个可重置的多路同步点,在某些并行编程风格中很有用。
Exchanger 允许两个线程在 collection 点交换对象,它在多流水线设计中是有用的。
并发 Collection
除队列外,此包还提供了设计用于多线程上下文中的 Collection 实现:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList 和 CopyOnWriteArraySet。
当期望许多线程访问一个给定 collection 时,ConcurrentHashMap 通常优于同步的 HashMap,ConcurrentSkipListMap 通常优于同步的 TreeMap。
当期望的读数和遍历远远大于列表的更新数时,CopyOnWriteArrayList 优于同步的 ArrayList。
此包中与某些类一起使用的“Concurrent&rdquo前缀;是一种简写,表明与类似的“同步”类有所不同。
例如,java.util.Hashtable 和 Collections.synchronizedMap(new HashMap()) 是同步的,但 ConcurrentHashMap 则是“并发的”。
并发 collection 是线程安全的,但是不受单个排他锁的管理。
在 ConcurrentHashMap 这一特定情况下,它可以安全地允许进行任意数目的并发读取,以及数目可调的并发写入。
需要通过单个锁不允许对 collection 的所有访问时,“同步”类是很有用的,其代价是较差的可伸缩性。
在期望多个线程访问公共 collection 的其他情况中,通常“并发”版本要更好一些。
当 collection 是未共享的,或者仅保持其他锁时 collection 是可访问的情况下,非同步 collection 则要更好一些。
大多数并发 Collection 实现(包括大多数 Queue)与常规的 java.util 约定也不同,因为它们的迭代器提供了弱一致的,而不是快速失败的遍历。
弱一致的迭代器是线程安全的,但是在迭代时没有必要冻结 collection,所以它不一定反映自迭代器创建以来的所有更新。
内存一致性属性
Java Language Specification 第 17 章定义了内存操作(如共享变量的读写)的 happen-before 关系。只有写入操作 happen-before 读取操作时,才保证一个线程写入的结果对另一个线程的读取是可视的。
synchronized 和 volatile 构造 happen-before 关系,Thread.start() 和 Thread.join() 方法形成 happen-before 关系。尤其是:
线程中的每个操作 happen-before 稍后按程序顺序传入的该线程中的每个操作。
一个解除锁监视器的(synchronized 阻塞或方法退出)happen-before 相同监视器的每个后续锁(synchronized 阻塞或方法进入)。
并且因为 happen-before 关系是可传递的,所以解除锁定之前的线程的所有操作 happen-before 锁定该监视器的任何线程后续的所有操作。
写入 volatile 字段 happen-before 每个后续读取相同字段。volatile 字段的读取和写入与进入和退出监视器具有相似的内存一致性效果,但不 需要互斥锁。
在线程上调用 start happen-before 已启动的线程中的任何线程。
线程中的所有操作 happen-before 从该线程上的 join 成功返回的任何其他线程。
java.util.concurrent 中所有类的方法及其子包扩展了这些对更高级别同步的保证。尤其是:
线程中将一个对象放入任何并发 collection 之前的操作 happen-before 从另一线程中的 collection 访问或移除该元素的后续操作。
线程中向 Executor 提交 Runnable 之前的操作 happen-before 其执行开始。同样适用于向 ExecutorService 提交 Callables。
异步计算(由 Future 表示)所采取的操作 happen-before 通过另一线程中 Future.get() 获取结果后续的操作。
“释放”同步储存方法(如 Lock.unlock、Semaphore.release 和 CountDownLatch.countDown)之前的操作 happen-before 另一线程中相同同步储存对象成功“获取”方法(如 Lock.lock、Semaphore.acquire、Condition.await 和 CountDownLatch.await)的后续操作。
对于通过 Exchanger 成功交换对象的每个线程对,每个线程中 exchange() 之前的操作 happen-before 另一线程中对应 exchange() 后续的操作。
调用 CyclicBarrier.await 之前的操作 happen-before 屏障操作所执行的操作,屏障操作所执行的操作 happen-before 从另一线程中对应 await 成功返回的后续操作。
对于“happen-before”等地方,还没完全搞懂,需要时间消化。
可参考:http://ifeve.com/easy-happens-before/,http://mapserver000-gmail-com.iteye.com/blog/1945688
江湖传言,《Java并发编程实践》这本书还是很不错的,2016年买本读读,最近先多研究点代码层次的东东。
转载于:https://www.cnblogs.com/qitian1/p/6462514.html