欢迎来到天天文库
浏览记录
ID:41033052
大小:52.00 KB
页数:5页
时间:2019-08-14
《JAVA并发编程》由会员上传分享,免费在线阅读,更多相关内容在工程资料-天天文库。
1、Java并发编程之之EditedbyMoDongsong一、线程安全之可见性线程安全就是在多线程访问的情况下,可以持续进行正确的行为。多线程环境中的共享变量不可见性是常见的非线程安全的一种。不少人都错误的认为,一个public变量其他对象都能访问,它就是可见的。在单线程环境下,是这样。但在多线程运行环境下,每个线程对变量改变时,其他线程并不一定都能即时看见。要保证可见性,必须同步。在多CPU的环境中,每个处理器会把修改的共享变量放在寄存器中,而只有写入到内存后,其他处理器才能看见。而现代处理器都会重排序执行顺序以提高性能,所以
2、在没有同步的情况下,缓存会改变写入到主内存的次序。最终可能导致运行的结果并不是程序原先预先的结果。这里给一个最简单常见的因为变量非可见性的非线程安全的例子。publicclassNotSafeValue{privateintvalue;publicintget(){returnvalue;}publicvoidset(intvalue){this.value=value}}在多线程环境下,即使看似set调用在前,get也不一定能拿到最新的值。有多种方式来保证共享变量的可变性:(1)加锁使用synchronized关键字来加锁,
3、这个大家都知道,是最常用的。比如上面的例子中,在每个get和set方法都加这个关键字就能保证线程安全了。当然java5.0后,还有显式锁。(2)使用volatile关键字在上面的例子中,给value变量的定义加找个关键字就是线程安全的了。从可见性的角度来说,volatile跟使用synchronized是一样的,而且性能优越很多。但是,volatile只能保证可见性,不能保证操作的原子性。所以不能滥用volatile。通常被当作标志状态使用,比如循环的停止标志。使用volatile,能保证其他线程对标志的改变都是即时的。(3)
4、使用原子变量java5.0后提供了原子变量类型。原子变量应该可以说是一种安全的volatile变量,既能保证可见性,还能保证操作的原子性,还有比较好的性能。如,可以使用AtomicLong类型的变量在多线程环境下来做自增长的计数变量。二、线程安全之原子性在多线程环境中原子性操作也是经常遇见的。比如计数器的实现。我们都知道可以实现原子操作的有三种方式:使用synchronized,使用原子变量和使用显式锁。而JDK中也定义了很多线程安全的类型,它们中的方法都是原子性的。比如vector和hashtable,还有java.util
5、.concurrent中的集合类。但在实际应用中也可能会犯这样的错误:publicvoidadd(Objecte){If(!vector.contains(e))vector.add(e);}contains和add都是原子的,但这是一个复合操作,并不能保证整个操作的原子性,还需要额外的锁。有人确实犯了这样的错误。而很多人都会犯这个错误:publicListlist=Collection.synchronizedList(newArrayList());publicsynchronizedvoidputIfAbsent(Obj
6、ecto){if(!list.contains(o))list.add(o);}看起来没有什么问题。但是list本身使用的锁并不是putIfAbsent所用的锁。所以这个操作不是原子的。应该:publicvoidputIfAbsent(Objecto){synchronized(list){if(!list.contains(o))list.add(o);}}当然,这是一个‘缺少即加入’实现。Java5.0之后有了并发容器。可以不用自己实现这样的功能了。一、线程安全之安全发布先来看一个例子:有一个正常的类NiceValuepu
7、blicclassNiceValue{privateintvalue;publicNiceValue(intvalue){this.value=value}publicvoidcheck(){if(n!=n)thrownewException(“WrongValue!”);}}还有一个类使用了类NiceValuepublicclassChecker{publicNiceValueniceValue;publicvoidinit(){niceValue=newNiceValue(1);}publicvoidrunCheck(){
8、for(inti=0;i<5;i++){newThread(){publicvoidrun(){init()niceValue.check();}}.start();}}Publicstaticvoidmain(Stringargs[]){newChecker().runCh
此文档下载收益归作者所有