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并发编程与实战》龙果学院