第2章 对象及变量的并发访问

synchronized同步方法

方法内的变量为线程安全

“非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程安全”问题,所得结果就是“线程安全”的了。这是方法内部的变量是私有的特性造成的。

实例变量非线程安全

如果多个线程共同访问1个对象中的实例变量,则有可能出现“非线程安全”问题。
用线程访问的对象中如果有多个实例变量,则运行的结果有可能出现交叉的情况。
如果对象仅有1个实例变量,则有可能出现覆盖的情况。
在两个线程访问同一个对象中的同步方法时一定是线程安全的。
关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当做锁。如果多个线程访问多个对象,则JVM会创建多个锁。
A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法。
A线程先持有object对象的Lock锁,B线程如果在这时调用object对象中的synchronized类型的方法则需等待,也就是同步。

脏读

发生脏读的情况是在读取实例变量时,此值已经被其它线程更改过了。

synchronized锁重入

关键字synchronized具有锁重入的功能,也就是在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的。
“可重入锁”的概念是:自己可以再次获取自己的内部锁。比如有1条线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象锁的时候还是可以获取的,如果不可重入锁的话,就会造成死锁。
可重入锁也支持在父子类继承的环境中。

出现异常,锁自动释放

同步不具有继承性

synchronized同步语句块

synchronized方法的弊端

用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间的任务,那么B线程则必须等待比较长时间。

静态同步synchronized方法与synchronized(class)代码块

synchronized(class)是对象锁;静态同步synchronized方法是Class锁,而Class锁可以对类的所有对象实例起作用。

多线程的死锁

Java线程死锁是一个经典的多线程问题,因为不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法继续完成。在多线程技术中,“死锁”是必须避免的,因为这会造成线程的“假死”。只要互相等待对方释放锁就有可能出现死锁。

volatile关键字

关键字volatile的主要作用是使变量在多个线程间可见。 使用volatile关键字最致命的缺点是是不支持原子性,使用volatile关键字增加了实例变量在多个线程之间的可见性。

关键字volatile和synchronized的比较:

1.关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,并且volatile只能修饰于变量,而synchronized可以修饰方法,以及代码块。
2.多线程访问volatile不会产生阻塞,而synchronized会产生阻塞。
3.volatile保证数据的可见性,但不能保证原子性;但synchronized可以保证原子性,也可以间接保证可见性,因为它会将私有内部和公共内存中的数据做同步。

线程安全包含原子性(同步性)和可见性两个方面。
关键字volatile主要使用的场合是在多个线程中可以感知实例变量被更改了,并且可以获得最新的值使用,也就是用多线程读取共享变量时可以获得最新值使用。

 

posted @ 2016-04-01 14:36  yly123  阅读(159)  评论(0编辑  收藏  举报