Java_并发编程培训

上传人:新** 文档编号:567914742 上传时间:2024-07-22 格式:PPT 页数:86 大小:5.32MB
返回 下载 相关 举报
Java_并发编程培训_第1页
第1页 / 共86页
Java_并发编程培训_第2页
第2页 / 共86页
Java_并发编程培训_第3页
第3页 / 共86页
Java_并发编程培训_第4页
第4页 / 共86页
Java_并发编程培训_第5页
第5页 / 共86页
点击查看更多>>
资源描述

《Java_并发编程培训》由会员分享,可在线阅读,更多相关《Java_并发编程培训(86页珍藏版)》请在金锄头文库上搜索。

1、Java并发编程龙浩在一个list中有过亿条的Integer类型的值,如何更快的计算这些值的总和?一个计算的问题一个计算的问题简单的方法:更快的CPU来遍历靠谱的方法:分而治之来处理进一步的方法:Fork/jion简单的方法靠谱么?简单的方法靠谱么?免费午餐已经结束免费午餐已经结束软件历史性地向并发靠拢软件历史性地向并发靠拢http:/ 必须将线程变量同步回主存后, 其他线程才能访问到。Ordering:通过java提供的同步机制或volatile关键字, 来保证内存的访问顺序。Cache coherency :它是一种管理多处理器系统的高速缓存区结构,其可以保证数据在高速缓存区到内存的传输中

2、不会丢失或重复。 Happens-before ordering:synchronized,volatile,final,java.util.concurrent.lock|atomic线程:先让路给内存模型线程:先让路给内存模型这里有详述:http:/is.gd/c8fhE (别迷恋哥,哥只是传说!)内存中的可见部分内存中的可见部分Stack-1Stack-2Stack-3GlobalsHeap线程:线程:synchronized类同步方法同步块同步内部锁分离锁分拆锁保证原子性和可见性保证原子性和可见性线程:线程:Java MonitorsThis figure shows the moni

3、tor as three rectangles. In the center, a large rectangle contains a single thread, the monitors owner. On the left, a small rectangle contains the entry set. On the right, another small rectangle contains the wait set. Active threads are shown as dark gray circles. Suspended threads are shown as li

4、ght gray circles. 线程:独占锁(线程:独占锁(synchronized)l非方法修饰符,注意方法覆写的时候需要加上synchronized;l经典的顺序锁问题(两个线程安全的方法放在一起线程安全么? )lgetClass的问题。l分拆前:思考问题,顺便教你一招!分拆前:思考问题,顺便教你一招!分拆不了人,工具还不能分拆么?对,买分拆不了人,工具还不能分拆么?对,买3个手机去个手机去线程:分拆锁线程:分拆锁线程:分离锁线程:分离锁分离锁负面作用:对容器加锁,进行独占访问更加困难,并且更加昂贵了。内存使用的问题:sina就曾经因为在Action层使用ConcurrentHashM

5、ap而导致内存使用过大,修改array后竟然单台服务器节省2G。线程:线程:static的案例的案例public class StaticThreadTest /线程避免调用这个;public static Tree tree = new Tree(“jizi”,“2”);public static void createTree(Tree trees) Tree t = tree; if(trees.getName().equals(pg)t.setName(ceshi);public static void main(String args) throws InterruptedExcep

6、tionExecutorService exec = Executors.newFixedThreadPool(10);for(int i=0;i10;i+) exec.execute(new TreeThread(i);Thread.sleep(50);exec.shutdown();exec.awaitTermination(1, TimeUnit.SECONDS);线程:可见性线程:可见性volatile关键字:1:简化实现或者同步策略验证的时候来使用它;2:确保引用对象的可见性;3:标示重要的生命周期的事件,例如:开始或者关闭。脆弱的volatile的使用条件:1:写入变量不依赖变量的

7、当前值,或者能够保证只有单一的线程修改变量的值;2:变量不需要和其他变量共同参与不变约束;3:访问变量时不需要其他原因需要加锁。private volatile boolean isInterrupted = false;任务的取消和线程超时任务的取消和线程超时线程中断线程中断教父教父Joshua Bloch说线程:说线程:1.对共享可变数据同步访问;2.避免过多的同步;3.永远不要在循环外面调用wait;4.不要依赖于线程调度器;5.线程安全的文档化;6.避免使用线程组。目录目录线程并发编程(juc)线程监控工具编程思想和实践Fork/Jion框架开始并发编程了开始并发编程了行动之前,拜神先

8、行动之前,拜神先1.Mr. concurrency ,当今世界上并发程序设计领域的先驱,著名学者。他是util.concurrent包的作者,JSR166规范的制定。2.图书著作Concurrent Programming in Java: Design Principles and Patterns。3.其” A Scalable Elimination-based Exchange Channel”和”Scalable Synchronous Queues”两篇论文列为非阻塞同步算法的经典文章。4.A fork/jion framework同样影响着java7。Doug LeaAmdahl

9、Amdahl定律定律并发编程:三大定律(并发编程:三大定律(1)讨论的是加速比(speedup)的问题Gustafson定律并发编程:三大定律(并发编程:三大定律(2)Gustafson假设随着处理器个数的增加,并行与串行的计算总量也是可以增加的。Gustafson定律认为加速系数几乎跟处理器个数成正比,如果现实情况符合Gustafson定律的假设前提的话,那么软件的性能将可以随着处理个数的增加而增加。Sun-Ni定律并发编程:三大定律(并发编程:三大定律(3)充分利用存储空间等计算资源,尽量增大问题规模以产生更好/更精确的解。总结不是总结不是API,是寂寞!,是寂寞!来个高清无码版来个高清无

10、码版ExecutorsExecutorExecutorServiceScheduledExecutorServiceCallableFutureScheduledFutureDelayedCompletionServiceThreadPoolExecutorScheduledThreadPoolExecutorAbstractExecutorServiceExecutorsFutureTaskExecutorCompletionServiceQueuesBlockingQueueConcurrentLinkedQueueLinkedBlockingQueueArrayBlockingQueue

11、SynchronousQueuePriorityBlockingQueueDelayQueueConcurrent CollectionsConcurrentMapConcurrentHashMapCopyOnWriteArrayList,SetSynchronizersCountDownLatchSemaphoreExchangerCyclicBarrierTimingTimeUnitLocksLockConditionReadWriteLockAbstractQueuedSynchronizerLockSupportReentrantLockReentrantReadWriteLockAt

12、omicsAtomicType, AtomicTypeArrayAtomicTypeFieldUpdaterAtomicMarkable,StampableReferenceThreadPoolExecutorThreadPoolExecutor:自己动手,丰衣足食!:自己动手,丰衣足食! public static ExecutorService newFixedThreadPool(int nThreads) return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBloc

13、kingQueue(); 1:线程池的大小最好是设定好,因为JDK的管理内存毕竟是有限的;2:使用结束,需要关闭线程池;3: Runtime.getRuntime().addShutdownHook(hook); 对不能正常关闭的线程做好相关的记录。Executors:ExecutorServicenewFixedThreadPoolnewFixedThreadPoolnewSingleThreadExecutornewSingleThreadExecutornewCachedThreadPoolnewCachedThreadPoolnewSingleThreadScheduledExecut

14、ornewSingleThreadScheduledExecutorExecutorService严重注意:别设置线程池无限大小入门版:入门版:CompletionService生产者消费者模式的简要实现版本。生产者消费者模式的简要实现版本。双剑合璧:双剑合璧:Future+Callable任务池:ScheduledExecutorServiceTimer+TimeTaskScheduledExecutorServcie + DelayQeuueQuartz计划任务执行相关的操作,使用使用java真幸福,选择多多!真幸福,选择多多!阻塞队列:阻塞队列:BlockingQueue抛出异常特殊值阻

15、塞超时插入插入add(e)offer(e)put(e)offer(e, time, unit)移除移除remove()poll()take()poll(time, unit)检查检查element()peek()不可用不可用Kaopuability:插入(offer);移除(poll)BlockingQueue 的诸侯领地的诸侯领地接口抽象类子类BlockingQueueAbstractQueueArrayBlockingQueueDelayQueueLinkedBlockingDequeLinkedBlockingQueuePriorityBlockingQueueSynchronousQu

16、eueArrayBlockingQueue:一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。Delayed 元素的一个无界阻塞队列,只有在延迟期满时才能从中提取元素.LinkedBlockingDeque一个基于已链接节点的、任选范围的阻塞双端队列。 LinkedBlockingQueue一个基于已链接节点的、范围任意的 blocking queue。此队列按 FIFO(先进先出)排序元素PriorityBlockingQueue一个无界阻塞队列,它使用与类 PriorityQueue 相同的顺序规则,并且提供了阻塞获取操作。SynchronousQueue一种

17、阻塞队列,其中每个插入操作必须等待另一个线程的对应移除操作 ,反之亦然。BlockingDeque:双端队列双端队列第一个元素(头部)第一个元素(头部)抛出异常特殊值阻塞超时期插入插入addFirst(e)offerFirst(e)putFirst(e)offerFirst(e, time, unit)移除移除removeFirst() pollFirst()takeFirst()pollFirst(time, unit)检查检查getFirst()peekFirst()不适用不适用最后一个元素(尾部)最后一个元素(尾部)抛出异常特殊值阻塞超时期插入插入addLast(e)offerLast(

18、e)putLast(e)offerLast(e, time, unit)移除移除removeLast() pollLast()takeLast()pollLast(time, unit)检查检查getLast()peekLast()不适用不适用并发集合并发集合:你值得拥有你值得拥有同步的不是同步的不是Map,是凤姐!是凤姐!ConcurrentHashMap:解放军解放军38军军你那飘逸的同步,分离锁的设计,再hash算法以及游离于多个Segment的耍心跳的各种操作,都深深的吸引了我。详细设计细节:http:/ List array = new ArrayList();public List

19、 list = new CopyOnWriteArrayList(array);同步器:四大金刚同步器:四大金刚CountDownLatchCyclicBarrierSemaphoreExchanger闭锁:闭锁:CountDownLatch等待启动信号线程A获得等待启动信号线程B获得等待启动信号线程C获得等待启动信号线程A运行,递减锁存器的计数线程B运行,递减锁存器的计数线程C运行,递减锁存器的计数等待完成信号继续启动信号+完成信号的模式N部分锁存器倒计数模式;当线程必须用这种方法反复倒计数时,可改为使用 CyclicBarrier典型应用:手动控制事务,从数据库读取多份数据做初始化;典型应

20、用:手动控制事务,从数据库读取多份数据做初始化;关卡:关卡:CyclicBarrierBarrierABCABCBarrierBarrierABCAbarrierAbarrier:Abarrierisacoordinationmechanosm(analgorithm)thatforcesprocesswhichparticipateinaconcurrent(ordistributed)algorithmtowaituntileachoneofthemhasreachedacertainpointinitsprogram.Thecollectionofthesecoordinationpoi

21、ntsiscalledthebarrier.Oncealltheprocesseshavereachedthebarrier,theyareallpermittedtocontinuepastthebarrier.信号量:信号量:Semaphore运行后释放信号(release();)线程C线程A线程B获取信号( acquire();)交换器:交换器:Exchanger1.数据分解和数据流分解的一种技巧,可被视为 SynchronousQueue 的双向形式。2.JDK5时支持2个线程之间交换数据,JDK6后支持多个。至今我没有用过锁云:你的柔情我永远不懂锁云:你的柔情我永远不懂内部锁互斥锁分

22、离锁分拆锁闭锁独占锁读写锁顺序锁互斥锁:互斥锁: ReentrantLockLock 更加灵活,性能更好interface Lock void lock();void lockInterruptibly() throws InterruptedException;boolean tryLock();boolean tryLock(long timeout, TimeUnit unit)throws InterruptedException;void unlock();Condition newCondition();支持多个Condition可以不以代码块的方式上锁可以使用tryLock,并指

23、定等待上锁的超时时间调试时可以看到内部的owner thread,方便排除死锁RenntrantLock支持fair和unfair两种模式互斥锁(公平与非公平)和内部锁性能对比图互斥锁(公平与非公平)和内部锁性能对比图200/200200/500200/1000 200/1500 200/2000500/200500/500500/1000 500/1500 500/200002000400060008000100001200014000内部锁非公平互斥锁公平互斥锁原子操作结论:非公平互斥锁和内部锁性能在结论:非公平互斥锁和内部锁性能在jdk6_17jdk6_17下性能基本一样。下性能基本一样

24、。测试机:酷睿2.66双核,2G内存,win7读写锁:读写锁: ReadWriteLockReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是独占的。ReentrantReadWriteLockReadLock WriteLock A线程B线程C线程线程1线程2线程3高深:高深:AbstractQueuedSynchronizerl为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量、事件,等等)提供一个框架;l基于JDK底层来操控线程调度,LockSupport

25、.park和LockSupport.unpark;l此类支持默认的独占 模式和共享 模式之一,或者二者都支持;l如果想玩玩它,请看CountDownLatch的源码。l当然,也可以去FutureTask这个类看看。目录目录线程并发编程(juc)线程监控工具编程思想和实践Fork/Jion框架Fork/Join Framework (1)WorkStealingFork/Join FrameworklFJTask框架是Cilk用到的设计方案的变体,相关系统依赖于轻量级可执行任务。这些框架都是像操作系统映射线程到CPU一样来映射任务到线程,从而开发单纯,有规律,有约束力的fork/join程序来执

26、行映射动作。l工作线程池是确定的,每个工作线程(Thread子类FJTaskRunner的一个实例)是处理队列中任务的标准线程。正常的,工作线程的数量和系统的CPU的数量是一致的。任何合乎情理的映射策略将把这些线程映射到不同的cpu。l所有的fork/join任务都是一个轻量级可执行类的实例,不是一个线程实例。在java中,独立的可执行任务必须实现Runnable接口并定义一个run()方法。在FJTask框架中,这些任务是FJTask的子类而不是Thread的子类,它们都实现了Runnable接口l一个简单的控制和管理设施(这里讲的是FJTaskRunnerGroup)设置工作池,从一个正常

27、的线程(例如java语言中的main()方法)调用启动执行提供的fork/join任务。Doug Lea论文:http:/gee.cs.oswego.edu/dl/papers/fj.pdfFork/Join 的案例:求数组中的最大值的案例:求数组中的最大值Fork/Join 运行测试结果运行测试结果阙值 = 500k阙值 = 50k阙值 = 5k阙值 = 500阙值 = -50Pentium-4 HT(2 个线程)1.01.071.02.82.2Dual-Xeon HT(4 个线程).883.023.22.22.438-way Opteron(8 个线程)1.05.295.734.532.0

28、38-core Niagara(32 个线程).9810.4617.2115.346.49表表 1. 在不同系统上从在不同系统上从 500k 个元素的数组中运行个元素的数组中运行 select-max 的结果的结果fork-join 池中的线程数量与可用的硬件线程(内核数乘以每个内核中的线程数)相等Fork/Join 有用的资源有用的资源表表 1. 在不同系统上从在不同系统上从 500k 个元素的数组中运行个元素的数组中运行 select-max 的结果的结果jsr166:http:/gee.cs.oswego.edu/dl/concurrency-interest/index.htmlJav

29、a理论与实践:应用fork-join框架:BrianGoetzhttp:/ -3unixviWindows 下面DIY方式很多,txt编辑器都是好东西线程监控:线程监控:Jconsole线程监控:线程监控:VisualVm本地本地下载地址:https:/ Dump Analyzerhttps:/ and swap,原子化的读-该-写指令处理竞争策略:单个线程胜出,其他线程失败,但不会挂起基本思想:基本思想:Atomic原子类原子类基于硬件CAS实现Atomic类分四组:计量器、域更新器、数组、复合变量更佳的volatile目标1:实现复杂算术运算:incrementAndGet、getAndI

30、ncrement等目标2:支持Java类型对象的CAS操作:compareAndSet基本思想:非阻塞算法基本思想:非阻塞算法一个线程的失败或挂起不影响其他线程J.U.C的非阻塞算法依赖Atomic算法里一般采用回退机制处理Atomic的CAS竞争对死锁免疫的同步机制目标:相对阻塞算法,减少线程切换开销、减少锁的竞争等。也是Lock-free,即无锁编程无锁栈算法:无锁栈算法:Treiber算法改进版:http:/ M S - q u e u e 算法是1 9 9 6 年由M a g e d . M .Michael and M. L. Scott提出的,是最为经典的并发FIFO队列上的算法,

31、目前很多对并发FIFO队列的研究都是基于这个算法来加以改进的。 MS-queue算法的队列用一个单链表来实现,包含两个基本的操作,enquene()和dequene() ,新节点总是从队尾最后一个元素后面加入队列,节点元素总是从队头删除。包含两个指针,head和tail,head总是自相链表头部的节点,指向的这个节点被当作是哑节点或哨兵节点,它保存的值是多少并无意义;tail总是指向链表中的一个节点,不一定是队尾元素。每个节点包含两个数据域值信息,即存放的数值信息和指向下一个节点的指针。每个指针对象,除了包含一个指向节点的指针外,还包含一个时间戳,初试时时戳为零,每修改一次指针,时戳增加一,在

32、64位系统中,无需考虑时戳溢出的影响。无锁队列算法:无锁队列算法:Optitmistic算法 Optimistic算法对于上面提到的MS-queue算法的改进就在于使用普通的store指令代替代价昂贵的CAS指令。 Optimistic算法的高效性在于使用双向链表表示队列,并且入队和出队操作都只需要一次成功的CAS操作。该算法保证链表总是连接的,next指针总是一致的,当prev指针出现不一致时通过调用fixList方法能够恢复到一致性状态。 同MS-queue算法一样,optimistic算法也用到了原子化的指令Compare-and-swap(CAS),CAS(a,p,n),原子化的将内存

33、地址a中的值与p进行比较,如果二者相等,就将n写入地址a中并返回true,否则返回false。由于optimistic算法使用了CAS指令,所以经典的ABA问题同样会出现,解决方案同MS-queue相同,即使用标签机制。论文地址:http:/nedko.arnaudov.name/soft/L17_Fober.pdfAtomic实现实现public final int incrementAndGet() for (;) int current = get(); int next = current + 1; if (compareAndSet(current, next) return nex

34、t; public final boolean compareAndSet(int expect, int update) return pareAndSwapInt(this, valueOffset, expect, update); 当 import sun.misc.Unsafe; 这个的时候,就因为各种问题(例如:专利)看不到源码了。好东东:好东东:AtomicReferenceLock-free的数据结构就靠这个了,无论你喜欢与否,玩无锁编程,你都绕不开这个类。看amino框架的源码,你会发现这个妞无处不在。当然,还是AtomicInteger比较实用,多线程计数的时候,你会喜欢的

35、。编程实践:使用更优的锁编程实践:使用更优的锁内部锁synchronized优化后的锁分离锁分拆锁无锁Lock-free编程实践:使用更优的锁编程实践:使用更优的锁ReentrantLock比较内部锁在JDK的性能提升对比编程实践:使用更优的锁编程实践:使用更优的锁读写锁对比互斥锁ReentrantLock的性能编程实践:缩小锁的范围编程实践:缩小锁的范围减少线程把持锁的时间避免在临界区进行耗时计算常见做法:缩小同步快常见做法:把一个同步块分拆成多个需要保证业务逻辑正确为前提编程实践:避免热点域编程实践:避免热点域热点域:每次操作,都需要访问修改的fieldseg. ConcurrentHas

36、hMap的size计算问题编程实践:编程实践:使用不变和使用不变和Thread Local 的数据的数据不变数据,即Immutable类型数据、在其生命周期中始终保持不变,可以安全地在每个线程中复制一份以便快速读取。ThreadLocal数据,只被线程本身使用,因此不存在不同线程之间的共享数据的问题。编程实践:编程实践:使用高并发容器使用高并发容器J.U.C的高效地线程安全的并发容器Amino提供更多非阻塞的容器编程实践:编程实践:高速缓存计算结果高速缓存计算结果利用空间换时间避免了重复计算相同的数据编程实践:编程实践:文档化对外接口的同步策略文档化对外接口的同步策略如果一个类没有明确指明,就

37、不要假设它是线程安全的编程实践:编程实践:安全发布安全发布NotThreadSafepublic class UnsafeLazyInitialization private static Resource resource; public static Resource getInstance() if (resource = null) resource = new Resource(); / unsafe publication return resource; ThreadSafepublic class SafeLazyInitialization private static Re

38、source resource; public synchronized static Resource getInstance() if (resource = null) resource = new Resource(); return resource; 编程实践:编程实践:安全发布安全发布ThreadSafepublic class EagerInitialization private static Resource resource = new Resource(); public static Resource getResource() return resource; Th

39、readSafepublic class ResourceFactory private static class ResourceHolder public static Resource resource = new Resource(); public static Resource getResource() return ResourceHolder.resource ; 编程实践:编程实践:安全发布安全发布NotThreadSafepublic class DoubleCheckedLocking private static Resource resource; public s

40、tatic Resource getInstance() if (resource = null) synchronized (DoubleCheckedLocking.class) if (resource = null) resource = new Resource(); return resource; 编程实践:编程实践:利用成熟的框架利用成熟的框架J.U.CAminohttp:/amino- (1)、Data Structures(论文:http:/ 10.1.1.104.8774&rep=rep1&type=pdf)LockFreeList、LockFreeSet、LockFreeOrderedList、LockFreeDeque、LockFreeBlockQueue、ParallelRBTree(2)、Parallel Patterns & functionsMasterWorker(类似ExecutorService)、WorkStealingScheduler编程实践:编程实践:利用成熟的框架利用成熟的框架(3)、Parallel functionsGraphAlg、ParallelPrefix、ParallelScanner、QuickSorter(4)、Atomics and STMMultiCAS、LockFreeBSTree书籍推荐:书籍推荐:Q&A

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 教学/培训

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号