The Java lock usage (2)

之前介绍了一下我们程序中锁的分类,这篇文章将着重讲讲,java中的锁。

Synchronized

众所周知,Java提供了synchronized字段来对代码块进行加锁。oracle给出一下解释:

You might wonder what happens when a static synchronized method is invoked, since a static method is associated with a class, not an object. In this case, the thread acquires the intrinsic lock for the Class object associated with the class. Thus access to class’s static fields is controlled by a lock that’s distinct from the lock for any instance of the class.

通过用Synchronized关键字来给代码块加锁,来看个例子

1
2
3
4
5
6
7
public void addName(String name) {
synchronized(this) {
lastName = name;
nameCount++;
}
nameList.add(name);
}

对于synchronized的代码块,同时只能一个线程执行。所以他其实就是上一篇讲到的独占锁。并且他是一把
非公平锁。

ReentrantLock

在Java SE5的concurrent库类中,引入了lock的显式互斥机制。相比较Synchronize的方式,Lock比较
麻烦,但是对于解决某些类型的问题来说,lock就更加灵活了。

ReentrantLock类实现了Lock接口,并提供了一些高级功能,主要有以下3项:

  1. 等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。

  2. 公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。

  3. 锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。

ReentrantLock的核心方法是lock(),unlock(),tryLock(),比如源代码中的i例子:

1
2
3
4
5
6
7
8
9
10
Lock lock = new ReentrantLock();
if (lock.tryLock()) {
try {
// manipulate protected state
} finally {
lock.unlock();
}
} else {
// perform alternative actions
}

ReentrantReadWriteLock

ReentrantReadWriteLock实现的是ReadWriteLock。核心方法是readLock,writeLock。实现了并发读、互斥写。但读锁会阻塞写锁,是一种悲观锁的策略。

因此在一些并发需求高的情况下我们可以用reentrantReadWriteLock。他默认为非公平锁,但也可以设置成公平锁,具体的实现可以看看
Doug Lea大大的源码。

StampedLock

当读线程太多,而写线程比较少的情况下,写线程就很有可能出现饿死情况。因此在这种情况下,1.8推出了
StampedLock。它是三种模式:写、读、乐观读,读的时候不影响写,通过stamp来控制变量的是否发生了改变。

下面是自带的一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class Point {
private double x, y;
private final StampedLock sl = new StampedLock();
void move(double deltaX, double deltaY) { // an exclusively locked method
long stamp = sl.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp);
}
}
double distanceFromOrigin() { // A read-only method
long stamp = sl.tryOptimisticRead();
double currentX = x, currentY = y;
if (!sl.validate(stamp)) {
stamp = sl.readLock();
try {
currentX = x;
currentY = y;
} finally {
sl.unlockRead(stamp);
}
}
return Math.sqrt(currentX currentX + currentY currentY);
}
void moveIfAtOrigin(double newX, double newY) { // upgrade
// Could instead start with optimistic, not read mode
long stamp = sl.readLock();
try {
while (x == 0.0 && y == 0.0) {
long ws = sl.tryConvertToWriteLock(stamp);
if (ws != 0L) {
stamp = ws;
x = newX;
y = newY;
break;
}
else {
sl.unlockRead(stamp);
stamp = sl.writeLock();
}
}
} finally {
sl.unlock(stamp);
}
}
}

好了,java中锁的例子,本文就先介绍到这里。具体Lea大大的JUL代码,也值得好好的品读~