




已阅读5页,还剩27页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Java多线程入阶 张利飞zhanglifei 内容列表 使用线程的经验 设置名称 响应中断 使用ThreadLocalExecutor ExecutorService和Future阻塞队列 put和take offer和poll drainTo线程间通信 lock condition wait notify notifyAllLock free atomic concurrentMap putIfAbsent CopyOnWriteArrayList关于锁的经验介绍并发流程控制手段 CountDownLatch Barrier定时器 ScheduledExecutorService 大规模定时器TimerWheel并发三大定律图书 相关网络资源 publicclassMyThreadextendsThread publicMyThread super threadname Overridepublicvoidrun TODOSomething MyThreadthread newMyThread thread start Threadthread newThread threadname Overridepublicvoidrun TODOSomething thread start Threadthread newThread Overridepublicvoidrun TODOSomething thread setName threadname thread start 启动线程的注意事项 无论何种方式 启动一个线程 就需要给它一个名字 这对排错诊断系统有帮助 否则诊断问题时 无法直观知道某个线程的用途 1 2 3 Threadthread newThread task 传入任务thread setName threadname thread start 4 Threadthread newThread task threadname thread start 5 要响应线程中断 thread interrupt Threadthread newThread interrupttest Publicvoidrun for TODOSomething if Thread interrupted break thread start Threadthread newThread interrupttest publicvoidrun for try doXXX catch InterruptedExceptione break catch Exceptione handleException thread start Publicvoidfoo throwsInterruptedException if Thread interrupted thrownewInterruptedException 程序应该对线程中断作出恰当的响应 ThreadLocal 顾名思义它是localvariable 线程局部变量 它的功用非常简单 就是为每一个使用该变量的线程都提供一个变量值的副本 是每一个线程都可以独立地改变自己的副本 而不会和其它线程的副本冲突 从线程的角度看 就好像每一个线程都完全拥有该变量 使用场景Tokeepstatewithathread user id transaction id logging id Tocacheobjectswhichyouneedfrequently隐式传参注意 使用ThreadLocal 一般都是声明在静态变量中 如果不断的创建ThreadLocal而且没有调用其remove方法 将会导致内存泄露 同时请注意 如果是static的ThreadLocal 一般不需要调用remove 任务的提交者和执行者 为了方便并发执行任务 出现了一种专门用来执行任务的实现 也就是Executor 由此 任务提交者不需要再创建管理线程 使用更方便 也减少了开销 java util concurrent Executors是Executor的工厂类 通过Executors可以创建你所需要的Executor 任务的提交者和执行者之间的通讯手段 TaskSubmitter把任务提交给Executor执行 他们之间需要一种通讯手段 这种手段的具体实现 通常叫做Future Future通常包括get 阻塞至任务完成 cancel get timeout 等待一段时间 等等 Future也用于异步变同步的场景 ExecutorServiceexecutor Executors newSingleThreadExecutor Callabletask newCallable publicObjectcall throwsException Objectresult returnresult Futurefuture executor submit task future get 等待至完成 有两种任务 RunnableCallableCallable是需要返回值的任务 阻塞队列 阻塞队列 是一种常用的并发数据结构 常用于生产者 消费者模式 在Java中 有很多种阻塞队列 ArrayBlockingQueue最常用LinkedBlockingQueue不会满的SynchronousQueuesize为0PriorityBlockingQueueCompletionService BlockingQueue Executor TransferQueue JDK7中更快的SynchronousQueue 使用阻塞队列 使用BlockingQueue的时候 尽量不要使用从Queue继承下来的方法 否则就失去了Blocking的特性了 在BlockingQueue中 要使用put和take 而非offer和poll 如果要使用offer和poll 也是要使用带等待时间参数的offer和poll 使用drainTo批量获得其中的内容 能够减少锁的次数 使用阻塞队列 finalBlockingQueueblockingQ newArrayBlockingQueue 10 Threadthread newThread consumerthread publicvoidrun for Objectobject blockingQ poll 杯具 不等待就会直接返回handle object 1 finalBlockingQueueblockingQ newArrayBlockingQueue 10 Threadthread newThread consumerthread publicvoidrun for try Objectobject blockingQ take 等到有数据才继续handle object catch InterruptedExceptione break catch Exceptione handleexception 2 X 使用阻塞队列 finalBlockingQueueblockingQ newArrayBlockingQueue 10 Threadthread newThread consumerthread publicvoidrun for try Objectobject blockingQ poll 1 TimeUnit SECONDS 防止死等if object null continue 或者做其他处理 catch InterruptedExceptione break catch Exceptione handleexception 3 3 实现一个简单的阻塞队列 1 classBlockingQ privateObjectnotEmpty newObject privateQueuelinkedList newLinkedList publicObjecttake throwsInterruptedException synchronized notEmpty if linkedList size 0 notEmpty wait returnlinkedList poll publicvoidoffer Objectobject synchronized notEmpty if linkedList size 0 notEmpty notifyAll linkedList add object 要执行wait操作 必须先取得该对象的锁 执行wait操作之后 锁会释放 被唤醒之前 需要先获得锁 要执行notify和notifyAll操作 都必须先取得该对象的锁 未取得锁就直接执行wait notfiy notifyAll会抛异常 实现一个简单的阻塞队列 2 classBlockingQ privateObjectnotEmpty newObject privateObjectnotFull newObject privateQueuelinkedList newLinkedList privateintmaxLength 10 publicObjecttake throwsInterruptedException synchronized notEmpty if linkedList size 0 notEmpty wait synchronized notFull if linkedList size maxLength notFull notifyAll returnlinkedList poll publicvoidoffer Objectobject throwsInterruptedException synchronized notEmpty if linkedList size 0 notEmpty notifyAll synchronized notFull if linkedList size maxLength notFull wait linkedList add object 分别需要对notEmpty和notFull加锁 分别需要对notEmpty和notFull加锁 实现一个简单的阻塞队列 3 classBlockingQ privateLocklock newReentrantLock privateConditionnotEmpty lock newCondition privateConditionnotFull lock newCondition privateQueuelinkedList newLinkedList privateintmaxLength 10 publicObjecttake throwsInterruptedException lock lock try if linkedList size 0 notEmpty await if linkedList size maxLength notFull signalAll returnlinkedList poll finally lock unlock publicvoidoffer Objectobject throwsInterruptedException lock lock try if linkedList size 0 notEmpty signalAll if linkedList size maxLength notFull await linkedList add object finally lock unlock 一个锁可以创建多个Condition 要执行await操作 必须先取得该Condition的锁 执行await操作之后 锁会释放 被唤醒之前 需要先获得锁 要执行signal和signalAll操作 都必须先取得该对象的锁 注意 未锁就直接执行await signal siganlAll会抛异常 ReentrantLock和Synchronized Synchronized是Lock的一种简化实现 一个Lock可以对应多个Condition 而synchronized把Lock和Condition合并了 一个synchronizedLock只对应一个Condition 可以说Synchronized是Lock的简化版本 在JDK5 Synchronized要比Lock慢很多 但是在JDK6中 它们的效率差不多 不要在Lock和Condition上使用wait notiffy notifyAll方法 使用AtomicInteger classCounter privatevolatileintcount 0 publicsynchronizedvoidincrement count publicintgetCount returncount 若要线程安全执行执行count 需要加锁 classCounter privateAtomicIntegercount newAtomicInteger publicvoidincrement count incrementAndGet publicintgetCount returncount get 使用AtomicInteger之后 不需要加锁 也可以实现线程安全 这是由硬件提供原子操作指令实现的 在非激烈竞争的情况下 开销更小 速度更快 java util concurrent中实现的原子操作类包括 AtomicBoolean AtomicInteger AtomicLong AtomicReference 使用Lock Free算法 classCounter privatevolatileintmax 0 publicsynchronizedvoidset intvalue if value max max value publicintgetMax returnmax classCounter privateAtomicIntegermax newAtomicInteger publicvoidset intvalue for intcurrent max get if value current if pareAndSet current value break else continue else break publicintgetMax returnmax get 若要线程安全 需要加锁 LockFree算法 不需要加锁 通常都是三个部分组成 循环 CAS CompareAndSet 回退 循环 CAS 回退 1 2 使用Lock Free算法 classCounter privateAtomicIntegermax newAtomicInteger publicvoidset intvalue intcurrent do current max get if value current break while pareAndSet current value publicintgetMax returnmax get 方案3和方案2的实现是一样的 只不过把for 换成了do while 3 进一步使用Lock Free数据结构 classBeanManager privateMapmap newHashMap publicObjectgetBean Stringkey synchronized map Objectbean map get key if bean null map put key createBean bean map get key returnbean classBeanManager privateConcurrentMapmap newConcurrentHashMap publicObjectgetBean Stringkey Objectbean map get key if bean null map putIfAbsent key createBean bean map get key returnbean 使用ConcurrentMap 避免直接使用锁 锁由数据结构来管理 ConcurrentHashMap并没有实现Lock Free 只是使用了分离锁的办法使得能够支持多个Writer并发 ConcurrentHashMap需要使用更多的内存 同样的思路用于更新数据库 乐观锁 publicclassSequenceDaoextendsSqlMapClientDaoSupport publicbooleancompareAndSet Stringname intvalue intexpect Mapparameters newHashMap parameters put name name parameters put value value parameters put expect expect UPDATEt sequenceSETvalue value WHEREname name ANDvalue expect intupdateCount getSqlMapClientTemplate update SpareAndSet parameters returnupdateCount 1 通过UpdateCount来实现CompareAndSet 三个部分 循环 CAS CompareAndSet 回退 publicclassSequenceService Transactional propagation Propagation NOT SUPPORTED publicsynchronizedvoidincrement StringsequenceName for intvalue dao getValue sequenceName if pareAndSet sequenceName value 1 value break 注意 乐观锁时必须使用 Transactional propagation Propagation NOT SUPPORTED 对比 使用悲观锁版本 publicclassSequenceDaoextendsSqlMapClientDaoSupport publicintgetValueForUpdate Stringname SELECTvalueFROMt sequenceWHEREname name FORUPDATEreturn Integer getSqlMapClientTemplate queryForObject Sequence getValueForUpdate name publicvoidset Stringname intvalue Mapparameters newHashMap parameters put name name parameters put value value UPDATEt sequenceSETvalue value WHEREname name getSqlMapClientTemplate update Sequence set parameters publicclassSequenceService Transactional propagation Propagation REQUIRED publicsynchronizedvoidincrement2 StringsequenceName intvalue dao getValueForUpdate sequenceName dao set sequenceName value 1 读取时 就开始加锁 Lock Free算法 可以说是乐观锁 如果非激烈竞争的时候 不需要使用锁 从而开销更小 速度更快 使用CopyOnWriteArrayList classEngine privateListlisteners newArrayList publicbooleanaddListener Listenerlistener synchronized listeners returnlisteners add listener publicvoiddoXXX synchronized listeners for Listenerlistener listeners listener handle classEngine privateListlisteners newCopyOnWriteArrayList publicbooleanaddListener Listenerlistener returnlisteners add listener publicvoiddoXXX for Listenerlistener listeners listener handle COW是一种很古老的技术 类似的并发数据结构有 ConcurrentSkipListMapConcurrentSkipListSetCopyOnWriteArrayListCopyOnWriteArraySet 适当使用CopyOnWriteArrayList 能够提高读操作时的效率 1 2 锁的使用 使用支持CAS的数据结构 避免使用锁 如 AtomicXXX ConcurrentMap CopyOnWriteList ConcurrentLinkedQueue 一定要使用锁的时候 注意获得锁的顺序 相反顺序获得锁 就容易产生死锁 死锁经常是无法完全避免的 鸵鸟策略被很多基础框架所采用 通过Dump线程的StackTrace 例如linux下执行命令kill 3 或者jstack l 或者使用Jconsole连接上去查看线程的StackTrace 由此来诊断死锁问题 外部锁常被忽视而导致死锁 例如数据库的锁 存在检测死锁的办法 存在一些预防死锁的手段 比如Lock的tryLock JDK7中引入的Phaser等 并发流程控制 使用CoutDownLatch finalintCOUNT 10 finalCountDownLatchcompleteLatch newCountDownLatch COUNT for inti 0 i COUNT i Threadthread newThread workerthread i publicvoidrun doxxxxcompleteLatch countDown thread start completeLatch await finalCountDownLatchstartLatch newCountDownLatch 1 for inti 0 i 10 i Threadthread newThread workerthread i publicvoidrun try startLatch await catch InterruptedExceptione return doxxxx thread start doxxxstartLatch countDown 当你启动了一个线程 你需要等它执行结束 此时 CountDownLatch也许是一个很好的选择 当你启动很多线程 你需要这些线程等到通知后才真正开始 CountDownLatch也许是一个很好的选择 为什么要使用CountDownLatch finalCountDownLatchlatch newCountDownLatch 1 Threadthread newThread worker thread publicvoidrun doxxxlatch countDown thread start latch await finalObjectcompleteSignal newObject Threadthread newThread worker thread publicvoidrun doxxxsynchronized completeSignal completeSignal notifyAll synchronized completeSignal thread start completeSignal wait finalLocklock newReentrantLock finalConditioncompleteSignal lock newCondition Threadthread newThread worker thread publicvoidrun doxxxlock lock try completeSignal signalAll finally lock unlock lock lock try thread start completeSignal await finally lock unlock 以上三种实现功能是一样的方案1使用CountDownLatch最简单 1 2 3 并发流程控制 使用CycliBarrier classPerformaceTest privateintthreadCount privateCyclicBarrierbarrier privateintloopCount 10 publicPerformaceTest intthreadCount this threadCount threadCount barrier newCyclicBarrier threadCount newRunnable publicvoidrun collectTestResult for inti 0 i threadCount i Threadthread newThread test thread i publicvoidrun for intj 0 j loopCount j doTest try barrier await catch InterruptedExceptione return catch BrokenBarrierExceptione return thread start privatevoiddoTest doxxx privatevoidcollectTe
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 音乐专业听力试题及答案
- 黑吉辽蒙金太阳2026届高三9月开学联考(26-1002C)地理试题及答案
- 安徽省九师联盟2026届高三9月开学联考政治(含答案)
- 《烹饪原料初加工工艺》项目一刀工与原料成形
- 钻石专业试题及答案大全
- 路面施工方案反光衣
- 库房物资搬运施工方案
- 地产开发合作协议示例
- 楼顶油漆施工方案
- DB32-T 4451.10-2023 医用影像设备临床使用管理与质量控制规范 第10部分:超声成像设备
- 九年级化学人教版基于特定需求设计和制作简易供氧器(教学设计)
- SCAMPER创新思维模型
- 乡镇庆中秋迎国庆活动方案
- 山东科学技术出版社小学一年级上册综合实践活动教案
- 2024口腔医学专业考核标准
- 大型群众性活动安全许可申请表
- 小学数学人教版-六年级上-第一单元-分数乘法-教材分析
- 百融云创风险决策引擎V5产品操作手册
- DZ∕T 0033-2020 固体矿产地质勘查报告编写规范(正式版)
- 思念混声合唱简谱
- 家庭健康指导员培训方案及流程
评论
0/150
提交评论