多线程:线程同步的几种方式

版权声明:本博客为记录本人学习过程而开,内容大多从网上学习与整理所得,若侵权请告知! https://blog.csdn.net/Fly_as_tadpole/article/details/86433606

1.synchronized同步方法 (静态方法锁住类对象,其它方法锁住实例对象)

    即有synchronized关键字修饰的方法。 

    由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 

    内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

2.synchronized同步代码块 (锁住标记的对象)

    即有synchronized关键字修饰的语句块。 

    被该关键字修饰的语句块会自动被加上内置锁,从而实现同步 

3.使用ReentrantLock实现线程同步
在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
     ReenreantLock类的常用方法有:
         ReentrantLock() : 创建一个ReentrantLock实例 
         lock() : 获得锁 

代码
         unlock() : 释放锁 
    注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用 

4.使用特殊域变量(volatile)实现线程同步(无法保证原子性的,写到这儿来只是强调一下,它只保证了可见性和有序性。

    a.volatile关键字为域变量的访问提供了一种免锁机制, 

    b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新, 

    c.因此每次使用该域就要重新计算,而不是使用寄存器中的值 

d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量 

e.

对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的。

您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:

·  对变量的写操作不依赖于当前值。

·  该变量没有包含在具有其他变量的不变式中。

可以使用的场景:

将volatile 变量作为状态标志使用(和lock差不多,但是volatile赋值true本来这种就是原子操作,所以就刚好可以使用。)

5.volatile(保证可见性和有序性)的一个重要作用就是和CAS结合,保证了原子性

      最简单的比如i++,用volatile可以保证取得的值是最新的,而cas操作可以保证你修改前后的值只+1,而不会覆盖掉别的线程已经修改过的值,如果别的线程已经修改过,CAS会自动不修改的。

      但是没有volatile时,原子性不保证可见性。

       CAS改完可能值还在缓存里,不会马上把工作内存中被修改后的值 写回 主内存。

CAS只解决了比较和更新的原子性的问题,要保证可见性,需要加锁或者是用volatile修饰变量。

1.      首先,声明共享变量为volatile;

2.      然后,使用CAS的原子条件更新来实现线程之间的同步;

3.      同时,配合以volatile的读/写和CAS所具有的volatile读和写的内存语义来实现线程之间的通信。

一句话:volatile变量的读/写和CAS可以实现线程之间的通信。把这些特性整合在一起,就形成了整个concurrent包得以实现的基石。
 

猜你喜欢

转载自blog.csdn.net/Fly_as_tadpole/article/details/86433606