日常小结-java中同步方式概述

来源:互联网 发布:2016年餐饮业数据分析 编辑:程序博客网 时间:2024/04/28 07:03

本文概述了一线java中三种实现同步的方式的异同,volatile、synchronized和Lock相关类

volatile

volatile 可以看成是一种轻量化的同步方式。它不会引起线程的切换和调度。
从原理上说volatile实际上是禁止缓存标志位。现代计算机cpu不会直接和内存交互,尤其是有多个cpu的计算机,通常会将内存中的一部分以缓存行的形式读取到缓存中,每个cpu都有自己的缓存,cpu直接与缓存进行交互以提高cpu效率。而volatile标志位产生两个结果,1会使得包含当前对象的缓存行立刻写回系统内存中。2会使得其他cpu中当前对象的缓存行失效。
由此原理会有一些volatile的优化技术,比如填充等,详见《java并发编程技术》P10
这里需要注意的是volatile只能实现单步操作的原子性,比如说读取或者写入,但是i++这种自增操作属于复合操作不能保证原子性。
volatile可以作为线程传递消息的一种方式。

synchronized

synchronized是java的管程技术的体现。管程的定义详见《现代操作系统》P77,在任意时刻管程中只会有一个活跃的进程。synchronized包括的代码块或者方法就是临界区。管程通常结合条件变量,但java没有使用条件变量,而是使用对象本身作为管程的锁,在任意时刻只有一个线程能拥有该对象作为进入管程的锁。同事所有对象都有wait和notify方法来实现类似条件变量的sleep和wakeup()操作但可以出现中断异常,需要java自己处理,synchronized使得java的所有对象都可以作为锁实现。
在1.5之前所有的synchronized都是重量级锁。在1.5之后synchronized的实现的锁分成了3个等级,即偏向锁、轻量级锁、重量级锁三种。所有对象的锁只能升级不能降级。
偏向锁用在无竞争状态下,如果一个锁总是被同一个线程获得,则这个锁只会被标记为偏向锁。如果出现竞争则撤销标记。偏向锁的获得和是否不需要cas操作来加锁和解锁。只需要修改对象头的markword即可。
轻量级锁使用自旋实现等待而不是使用阻塞。如果自旋失败则会膨胀成为重量级锁。自旋会消耗cpu时间。但是少量的消耗时间代价抵得上上下文切换的代价。并且得到相应快的响应时间
重量级锁就是典型概念中的锁。使用阻塞等待其他线程释放锁。需要上下文切换,追求的是最大吞吐量,不消耗cpu。

除了偏向锁之外所有的锁都需要使用CAS实现。具体的实现请见《java并发编程艺术》P12-P16.

Lock

相对与synchronized,lock是更为精细的调控锁的方式。比如synchronized必须使用代码块或者方法包裹,在获取和释放多个锁时必须安装相应的顺序和可见性释放,而lock就没有这样的要求。而且lock也具有阻塞获取和一定时限获取等更为灵活的操控方式。但是通常需要编程人员自己捕获异常。
Lock的使用还可以结合条件变量condition。Lock在java中的基本实现是ReentrantLock。而ReentrantReadWriteLock是读写锁。

0 0
原创粉丝点击