JAVA锁机制

锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility).可见性就是释放锁之前的共享数据更改对随后获得锁的线程是可见的。

1 Synchronized

使用:synchronized可加在方法上,也可加在特定代码块上,括号中表示需要锁的独享
性能:托管给JVM执行,Java1.6后性能提升到与Lock差不多,官方更提倡使用。
场景:普通场景推荐使用。

2 Lock

使用:通常使用ReentrantLock重入锁,显示指定起始位置和终止位置。加锁和解锁处使用lock()unlock()方法,一般在finally块中写unlock()防止死锁。
性能:用JAVA写的控制锁代码
场景:复杂同步应用推荐自定义使用。比如中断线程控制权,自定义wait-nitify线程,公平锁等。
实现:Lock接口的实现基本都是通过聚合了一个队列同步器的子类来完成线程访问控制的。
区别:ReentantLock表现为API层面的互斥锁,synchronized表现为原生语法层面的互斥锁。
优点:Lock提供了synchronized关键字不具备的主要特性:
1.尝试非阻塞地获取锁;
2.能被中断地获取锁;
3.超时获取锁。

独占锁:同一时间只有一个线程获取锁。再有线程尝试加锁,将失败。 例如reentrantLock
共享锁:同一时间可以有多个线程获取锁。例如FutureTask

3 扩展:volatile

3.1 解释
volatile用在多线程,同步变量。线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。volatile告诉jvm,它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A)
volatile会告知程序任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性。

3.2 volatile与sychronized区别
volatile是程度较轻的synchronized,具备可见性,不具备操作原子性。volatile只是在线程内存和“主”内存间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值,确保多个线程在同一时刻,只能由一个线程处于方法或同步块中,这保证了线程对变量访问的可见性和排他性。

volatilesynchronized的使用和执行成本更低,不会引起线程上下文的切换和调度。Volatile一般情况下不能代替sychronized,因为volatile不能保证操作的原子性,即使只是i++,实际上也是由多个原子操作组成:read i; inc; write i,假如多个线程同时执行i++,volatile只能保证他们操作的i是同一块内存,但依然可能出现写入脏数据的情况。

推荐阅读更多精彩内容