package com.roocon.thread.ta1;

public class Sequence { private MyLock lock = new MyLock(); private int value; public int getNext() {
lock.lock();
value++;
lock.unlock();
return value; } public static void main(String[] args) { Sequence s = new Sequence(); new Thread(new Runnable() { @Override
public void run() {
while(true)
System.out.println(s.getNext());
}
}).start();
new Thread(new Runnable() { @Override
public void run() {
while(true)
System.out.println(s.getNext());
}
}).start();
new Thread(new Runnable() { @Override
public void run() {
while(true)
System.out.println(s.getNext());
}
}).start();
new Thread(new Runnable() { @Override
public void run() {
while(true)
System.out.println(s.getNext());
}
}).start();
new Thread(new Runnable() { @Override
public void run() {
while(true)
System.out.println(s.getNext());
}
}).start();
} }
 
 
package com.roocon.thread.ta1;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock; public class MyLock implements Lock { private boolean isLocked = false; @Override
public synchronized void lock() { while (isLocked) {//如果不是第一个进来的线程,就需要等待
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isLocked = true;//第一个进来的线程获得锁,不需要等待 } @Override
public synchronized void unlock() {
isLocked = false;
notify();//wait notify 必须和synchronized一起使用
} @Override
public void lockInterruptibly() throws InterruptedException { } @Override
public boolean tryLock() {
return false;
} @Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
} @Override
public Condition newCondition() {
return null;
}
}
 

运行结果:

 
1
2
3
4
5
6
7
...
 

现在来模拟下,基于以上代码,锁是否可重入:

 
package com.roocon.thread.ta1;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class Demo {
MyLock lock = new MyLock(); public void a() {
lock.lock();
System.out.println("a");
b();
lock.unlock();
} public void b() {
lock.lock();
System.out.println("b");
lock.unlock();
} public static void main(String[] args) {
Demo d = new Demo();
new Thread(new Runnable() {
@Override
public void run() {
d.a(); //输出a,并且一直处于等待状态,程序并未运行结束
}
}).start();
}
}
 

分析以上运行结果:

线程1调用a方法,第一次进入lock方法,去获取锁。此时,isLocked为false,于是将标志锁改为true。然后,输出a。再去执行b方法。此时,再次去调用lock方法。lock方法是使用

synchronized修饰的,是可重入的,于是继续执行b方法中的代码。判断isLocked,由于之前进入拿到了锁,因此isLocked为true,于是,会一直等待等待。这就是为什么输出a一直等待的原因。

为了实现可重入锁的效果,改进代码如下:

 
package com.roocon.thread.ta1;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock; public class MyLock implements Lock { private boolean isLocked = false;
private Thread lockBy = null;
private int lockCount = 0; @Override
public synchronized void lock() {
if (isLocked && lockBy != Thread.currentThread()) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isLocked = true;
lockBy = Thread.currentThread();
lockCount++; } @Override
public synchronized void unlock() {
if (lockBy == Thread.currentThread()) {
lockCount--;
if (lockCount == 0) {
isLocked = false;
notify();//wait notify 必须和synchronized一起使用
}
} } @Override
public void lockInterruptibly() throws InterruptedException { } @Override
public boolean tryLock() {
return false;
} @Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
} @Override
public Condition newCondition() {
return null;
}
}
 

运行结果:

a
b

解释以上运行结果:

线程1调用a方法,执行lock方法。线程1第一次进入,获得锁,于是,将isLocked设置为true,且lockBy为当前线程Thread1,同时,lockCount=1。

输出a后,再次执行代码调用b方法,synchronized可重入,再次调用b方法中的lock。此时,isLocked为true,但是,只有lockBy和当前线程相等,不满足wait操作条件,因此,

它会再次执行后面的代码,于是,lockCount=2。然后,在输出b之后,它会执行b方法中的unlock,解锁,但是,要明确,只有当线程1将它所有的锁都释放完毕后,才会去通知那些wait等待的线程。因此,需要加入对lockCount的判断,只有lockCount为0时,才将isLock的标志位改为false,同时通知其他线程可以去获取锁了。

参考资料:

《java并发编程与实战》龙果学院

05-01 02:20