Java锁有如下概念:
volatile
synchronized
ReentrantLock
在Java理论与实践系列中对此有过介绍分析:
正确使用 Volatile 变量
JDK 5.0 中更灵活、更具可伸缩性的锁定机制
在此对其中的概念再做一些深入的分析与解释:
1. volatile
提到volatile,很多地方都提及到的是volatile只能保证“可见性”无法保证“原子性”,首先的问题就是什么是可见性,为什么会存在可见性问题。其次通过几个例子说明一下可见性和原子性的区别。
可见性问题主要指一个线程修改了共享变量值,而另一个线程却看不到。引起可见性问题的主要原因是每个线程拥有自己的一个高速缓存区——线程工作内存。深入的原理分析可以参考如下两篇文章:
深入分析Volatile的实现原理
volatile的使用及其原理
通过如下代码可以验证一下volatile不能保证原子性:
public class VolatileTest {
public static void main(String[] args) {
int count = 1000;
Test test = new Test();
for (int i = 0; i < count; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.increment();
}
}).start();
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("count is " + test.getCount());
}
private static class Test {
private volatile int count = 0;
void increment() {
count++;
}
int getCount() {
return count;
}
}
}
如果volatile能够保证原子性的话,输出结果应该是1000,但实际上输出结果不确定,可能是992,982。
2. synchronized
还是上面的例子,略作改动,去掉volatile, increment方法定义为synchronized,则可以保证操作原子性,每次输出结果都是1000。
private static class Test {
private int count = 0;
synchronized void increment() {
count++;
}
int getCount() {
return count;
}
}
关键字有如下用法修饰的对象有如下几种:
修饰一个代码块
public void run() {
synchronized(this) {
// code block here
}
}
private Object lock;
public void run() {
synchronized(lock) {
// code block here
}
}
修饰一个方法
public synchronized void run() {
// code block here
}
修饰一个静态方法
public synchronized static void run() {
// code block here
}
修饰一个类
public class Test {
public void run() {
synchronized(Test.class) {
// code block here
}
}
}
synchronized的本质是获取对象锁,因此关键有两点:
锁定的对象,锁定的范围
针对上述几种情况:
修饰一个代码块:锁定的对象是synchronized(xxx)所指定的xxx对象,锁定的范围是{}所包含的代码块
修饰一个方法:锁定的对象是调用该方法的类实例,锁定的范围是该方法
修饰一个静态方法:锁定的对象是该类,即xxx.class对象,锁定的范围是该方法
修饰一个类:实际上是修饰代码块的特例,对象是某个类,即xxx.class
3. ReentrantLock
synchronized 关键字的特点是编码简单,不需要考虑加锁/释放的问题,缺点是不能应对复杂的应用场景,效率不高。为此Java提供了ReentrantLock类,详细介绍分析可以参考:
4. 其他
此外还有一些比较有用的包装可以供我们选择,不需要重新造轮子:
BlockingQueue:适用于典型的生产者/消费者模式