在Java多线程编程中,对共享资源进行互斥访问有多种实现方式,如:syncronized,ReentrantLock等。
在此,实现一个使用方式与ReentrantLock相似的自定义锁(注:在实际开发中,直接使用ReentrantLock即可)。
第一版:简单实现。
public class MyLockSimple {
private boolean flag = false;
public void lock() {
synchronized (this) {
while(flag) {
try {
wait(); // 已经加锁,当前线程需要等待
} catch (InterruptedException e) {
}
}
flag = true;
}
}
public void unlock() {
synchronized (this) {
flag = false;
notifyAll(); // 释放锁时通知其他线程
}
}
}
仅仅从功能上讲,上述简单版的锁实现是可以的。但是,存在如下2个问题:
1. 如果某个线程连续多次调用lock(),就会自己把自己锁住。
2. 如果某个线程并未执行lock(),而是直接执行unlock(),这样当前线程就可以unlock()其他线程的锁,是不合理的。
为了解决这两个问题,还应该进一步做如下处理:
1. 如果线程已经加锁,则不需要再加锁,避免自己把自己锁住。
2. 如果线程自己并未加锁,则不能释放锁,避免未获得锁的线程释放其他线程的锁。
public class MyLockGood {
private int locks = 0;
private Thread owner = null;
public void lock() {
synchronized (this) {
Thread me = Thread.currentThread();
while (locks > 0 && me != owner) {// 如果其他线程已经加锁,且不是当前线程自己加的锁,则等待
try {
wait();
} catch (InterruptedException e) {
}
}
// 如果自己已经获得锁,lock数就别增加了
if(owner == me && locks > 0) {
return;
}
owner = me;
locks++;
}
}
public void unlock() {
synchronized (this) {
Thread me = Thread.currentThread();
if(locks == 0 || me != owner) {// 没有加锁,或者当前加锁的线程不是自己,不需要解锁
return;
}
locks--;
owner = null;
notifyAll();
}
}