`
snake1987
  • 浏览: 71880 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java并发你也许不知道的(读Java Concurrency in Practice)

    博客分类:
  • java
阅读更多
1.线程安全
a.无状态的类是线程安全的
b.所有状态都具有原子性的类是线程安全的
原子性:即对该类的操作是不被打断的,即使在多线程的环境下
如果一个类只有单个状态,推荐使用jdk中的java.util.concurrent.atomic包AtomicBoolean
AtomicInteger
AtomicIntegerArray
AtomicIntegerFieldUpdater
AtomicLong
AtomicLongArray
AtomicLongFieldUpdater
AtomicMarkableReference
AtomicReference
AtomicReferenceArray
AtomicReferenceFieldUpdater
AtomicStampedReference
这些类作为状态都具有原子性
2.Synchronized
a.如果一个方法用Synchronized关键字修饰,则调用该方法所用的锁,为调用方法的对象的固有锁(如反射),如果同时带有Static关键字修饰,则使用的锁为该方法所在的class对象的固有锁。
固有锁:每个对象都隐性地带有一个锁,该锁为重入锁(重入锁将在后文介绍),用于synchronized关键字
像Vector,HashTable这样的类,其实就是用了类的固有锁,这该锁限制每个该类的方法都必须先获得该锁,才能继续执行

3.重入锁
关于重入锁的解释用书中英文的解释会更准确:But because intrinsic locks are reentrant, if a thread tries to acquire a lock that it already holds, the request succeeds.

可能看完上面的还是有点难理解
举一个书中的例子:
看以下代码

假设不是可重入锁,那会出现一个什么现象?
调用super.doSomething()时发现该方法被锁住了,然后等待,但等待的锁自己正持有着,也就变成了死锁

重入锁的实现:
重入锁是通过一个count和记录owner--一个持有该锁的Thread来实现的。当count值为0,认为这个锁当前没被任何线程持有。当一个线程持有了该锁了,jvm就会把owner置为该线程,并把count置为1,如果同样锁线程再次请求该锁,那jvm就会把count+1,如果线程退出同步块,则count-1,当count为0时,锁就释放了。

4.线程状态的锁操作
对于每一个涉及到多个变量的不变量,所有涉及到的变量都应该用同一个锁来进行同步
怎么理解呢?
看例子:

在vector中,每个方法都是用synchronized修饰的,但在上面的使用中--如果两个线程先后进入该语句块,再轮流执行vector.contain(element),显然还是会添加两次同样的element到vector中,所以还是不能保证vector的原子性

5.程序中的代码是可能被打乱的
如果没有进行同步,编译器,进程,和运行环境将有可能会打乱运行的顺序。
如文中所举例子:

将有可能出现这样的状况:输出结果为0.
这是因为执行的顺序被打乱了

6.64位数据的读或写是非原子性的
一般的数据类型,如int,执行
int a = 1;
int b = a;
这些操作都是原子操作,但是像long,double就不是了
jvm是允许把64位数据的读和写分开两次操作的,每次操作32位。
因此,有些项目,我们对某些数据的实时性不会太在意,就不会定义该变量为原子变量,但如果是long或者double类型,就要小心了。很有可能某用户在读取的时候读到的是前一个数据的前32位,和后一个数据的后32位

7.volatile关键字
当一个变量用volatile声明了,编译器会放一个notice到该变量的共享区,然后当执行的时候,就不会对这个变量在程序中的执行顺序进行修改。并且volatile不会缓存在寄存器中,也不会缓存在别的进程中,因此,读volatile修饰的变量时总能返回一个最新更新的值。

使用锁能同时保证变量的可见性和原子性,但volatile只能保证其可见性。

什么时候不适合使用volatile?
举一个经典的例子:i++操作,在并发环境下volatile是不能保证其正确性的

什么时候可以用volatile?
* 该变量的值不依赖该变量当前的值,像i++,或者你能保证该变量的更新只在单线程的环境下出现
* 该变量不和其他的变量一起包含在一个不变量中,如上文的vector
* 由于其他的原因,该变量不需要使用锁
  • 大小: 12.1 KB
  • 大小: 3.8 KB
  • 大小: 19.2 KB
1
0
分享到:
评论
2 楼 snake1987 2011-03-29  
NanguoCoffee 写道
用4来检验1.b,就发现1.b是不对的。


像Vecotr那样的,其实是线程安全的,因为按照他的定义,他的每个方法都是线程安全的,关键是你用了两个方法来执行一个原子性操作,这是别人方法定义中没有注明的
这与线程安全的概念是不违背的
1 楼 NanguoCoffee 2010-09-06  
用4来检验1.b,就发现1.b是不对的。

相关推荐

Global site tag (gtag.js) - Google Analytics