




全文预览已结束
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Java并发编程之之Edited by Mo Dongsong一、 线程安全之可见性线程安全就是在多线程访问的情况下,可以持续进行正确的行为。多线程环境中的共享变量不可见性是常见的非线程安全的一种。 不少人都错误的认为,一个public变量其他对象都能访问,它就是可见的。在单线程环境下,是这样。 但在多线程运行环境下,每个线程对变量改变时,其他线程并不一定都能即时看见。要保证可见性,必须同步。在多CPU的环境中,每个处理器会把修改的共享变量放在寄存器中,而只有写入到内存后,其他处理器才能看见。而现代处理器都会重排序执行顺序以提高性能,所以在没有同步的情况下,缓存会改变写入到主内存的次序。最终可能导致运行的结果并不是程序原先预先的结果。 这里给一个最简单常见的因为变量非可见性的非线程安全的例子。 public class NotSafeValueprivate int value;public int get()return value;public void set(int value) this.value=value在多线程环境下,即使看似set调用在前,get也不一定能拿到最新的值。有多种方式来保证共享变量的可变性:(1)加锁使用synchronized 关键字来加锁,这个大家都知道,是最常用的。比如上面的例子中,在每个get和set方法都加这个关键字就能保证线程安全了。当然java 5.0后,还有显式锁。(2)使用volatile 关键字在上面的例子中,给value 变量的定义加找个关键字就是线程安全的了。从可见性的角度来说,volatile跟使用synchronized是一样的,而且性能优越很多。但是,volatile只能保证可见性,不能保证操作的原子性。所以不能滥用volatile。通常被当作标志状态使用,比如循环的停止标志。使用volatile,能保证其他线程对标志的改变都是即时的。 (3)使用原子变量 java 5.0后提供了原子变量类型。原子变量应该可以说是一种安全的volatile变量,既能保证可见性,还能保证操作的原子性,还有比较好的性能。如,可以使用AtomicLong类型的变量在多线程环境下来做自增长的计数变量。二、 线程安全之原子性在多线程环境中原子性操作也是经常遇见的。比如计数器的实现。我们都知道可以实现原子操作的有三种方式:使用synchronized, 使用原子变量和使用显式锁。而JDK中也定义了很多线程安全的类型,它们中的方法都是原子性的。比如vector和hashtable,还有java.util.concurrent中的集合类。但在实际应用中也可能会犯这样的错误:public void add(Object e)If (!vector.contains(e) vector.add(e);contains和add都是原子的,但这是一个复合操作,并不能保证整个操作的原子性,还需要额外的锁。有人确实犯了这样的错误。而很多人都会犯这个错误:public List list= Collection.synchronizedList(new ArrayList();public synchronized void putIfAbsent(Object o) if (! list.contains(o) list.add(o);看起来没有什么问题。但是list本身使用的锁并不是putIfAbsent所用的锁。所以这个操作不是原子的。应该:public void putIfAbsent(Object o) synchronized(list) if (! list.contains(o) list.add(o);当然,这是一个缺少即加入实现。Java 5.0之后有了并发容器。可以不用自己实现这样的功能了。三、 线程安全之安全发布先来看一个例子: 有一个正常的类 NiceValuepublic class NiceValue private int value; public NiceValue(int value)this.value=value public void check() if(n!=n) throw new Exception(“Wrong Value!”); 还有一个类使用了类NiceValuepublic class Checker public NiceValue niceValue; public void init() niceValue=new NiceValue(1); public void runCheck()for(int i=0;i5;i+) new Thread() public void run() init() niceValue.check(); .start(); Public static void main(String args) new Checker().runCheck(); 在多CPU环境中,多次运行Checker,就会发现有时竟然会抛出异常!通常情况下,看类NiceValue, check方法怎么可能会抛出异常呢。但事实确是了。这是因为Checker对NiceValue做了不安全的发布使方法check可能读取了过期值。具体原因跟变量的可见性是一样的。多个线程访问了公共变量niceValue, 使niceValue中的value变量在多线程环境中不可见了。对NiceValue来说,它没有线程安全性的问题,但是Checker对它的不正确的发布,导致了线程的安全问题。而有关发布的问题,最长遇见的是单实例模式的延迟初始化问题。我们都能明白下面的方式是不安全的。public class SingletonC private static SingletonC instance; public static SingletonC getInstance() if(instance=null) instance=new SingletonC(); return instance; 然后我们大多会通过加锁来保证线程安全。当然还有更有效的方式:public class SingletonC private static class SingletonCHolder public static SingletonC instance=new SingletonC(); public static SingletonC getInstance() return SingletonrCHolder.instance; 四、 内部锁与显式锁在多线程编程中,synchronized是大家熟悉和经常用的,这也是java的内置锁。它可以强制原子性和可见性。这没有什么可多说的。Java 5.0 提供了新的选择:显式锁ReentrantLock。ReentrantLock在获取和释放锁方面都提供了与synchronized的语义。1、显式锁与内部锁的区别:不能中断正在等待获取内部锁的线程,必须在获取内部锁的代码块中释放内部锁。而显式锁是可中断的,可定时的,显式锁必须在finally块中释放。使用方式如:Lock lock=new ReentrantLock(); lock.lock(); /这个方法会一直等,不可中断try finally lock.unlock(); if (lock.tryLock() /没有获取锁,不等, try finallylock.unlock();if(lock.tryLock(3,SECONDS) /如果没有获取锁,继续尝试3秒钟 try finallylock.unlock(); lock.lockTerrruptibly(); /可中断,抛出InterruptedException 异常try finally lock.unlock(); 注意:一定要记得在finally块中释放锁,这通常也是显示锁的一个风险。 2、性能对比 在java 5.0,显式锁跟内部锁比,有很大的性能提升。但是java 6也改善了内部锁的实现算法,使用了类似显式锁的算法。内部锁的性能已经很接近显式锁了。3、锁的选择Java 6中,内部锁的性能已经非常接近显式锁了。而且,内部锁使用比较简洁,而显式锁还存在忘记在finally块中释放的风险。如果能用内部锁解决,就尽量用内部锁。4、读写锁Java 5.0还提供了一个很特殊的锁:读写锁ReadWriteLock。有时会很有用的哦。它允许多个线程来同时读取,但是只允许一个线程写。很明显,这可能会带来性能的提升。例子:public class ReadWriteData private final Map map; private final ReadWriteLock lock=new ReentrantReadWriteLock(); private final Lock rLock=lock.readLock(); private final Lock wLock=lock.writeLock(); public ReadWriteData(Map
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年航空机务工程师职业资格评定试题及答案解析
- 高粱购销合同模板(3篇)
- n2级护理岗位考试试题及答案
- 环保项目投资民间借款合同
- 任城区人才公寓租住管理与租客权益保障协议
- 商业地产业主与物业物业服务合同范本
- 股权转让协议范本中的业绩承诺条款详解
- 2025公务员能源局面试题目及答案
- 辅警专业知识试题及答案
- 跳棋的教学课件怎么写
- 新高考高中英语熟词生义485例(精校版)重点单词、短语辨析
- 斜视检查(斜视诊疗课件)
- 和安风电场电气设备定检及预防性试验技术规范
- 农产品食品安全评价技术 课件全套 模块1-8 走进农产品食品安全检测 - 油脂脂肪酸组成和溶剂残留检测
- (正式版)HGT 22820-2024 化工安全仪表系统工程设计规范
- 第二章 临床康复工程学基础
- (高清版)TDT 1075-2023 光伏发电站工程项目用地控制指标
- 《水生生物学桡足类》课件
- 《预算员培训二》课件
- 八年级劳动课下册教案
- 人工动静脉瘘狭窄查房
评论
0/150
提交评论