1.Lock是一个接口,定义了一系列的获取和释放锁的方法。
接口 | 备注 |
lock() | 获取锁,获取不到则阻塞 |
tryLock() | 尝试获取锁,如果获取不到立即返回 |
tryLock(long time, TimeUnit unit) | 在指定时间内尝试获取锁,如果获取不到立即返回 |
lockInterruptedly() | 获取锁时可以响应中断 |
2.Lock和synchronized的比较
Lock需要显示地获取和释放锁,繁琐但更灵活,可以方便的实现公平性地获取锁,非阻塞地获取锁,能被中断地获取锁,超时获取锁。synchronized不需要显示地获取和释放锁,使用简单,但是不灵活。
3.自己实现一个锁
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 void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public synchronized void unlock() {
isLocked = false;
notify();
}
@Override
public Condition newCondition() {
return null;
}
}
解决计数器线程安全问题。
public class Sequence {
private int value;
private MyLock lock = new MyLock();
public int getNext() {
try {
lock.lock();
return value++;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
final Sequence s = new Sequence();
for (int i = 0; i < 4; i++) {new Thread(new Runnable() {
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + " " + s.getNext());
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
}
3.可重入锁
使用第3步我们自己实现的锁完成以下代码。
public class Demo {
private 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 demo = new Demo();
demo.a();
}
}
运行后我们发现只打印出来了a,并且程序没有退出。这是因为第三步我们实现的锁不是可重入的,在方法a中获取了锁,但在执行方法b时还需要获取锁,但此时锁有没有被自己释放,所以线程被自己阻塞。为了解决这种问题,我们可以实现自己的可重入锁,可重入锁的意思是一个线程获得锁以后,再次获取相同的锁不用进行同步操作,可以直接获取锁。
public class MyReentrantLock implements Lock {
private boolean isLocked = false;
private Thread lockBy = null;
private int lockCount = 0;
@Override
public synchronized void lock() {
Thread currentThread = Thread.currentThread();
while (isLocked && currentThread != lockBy) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isLocked = true;
lockBy = currentThread;
lockCount++;
}
@Override
public synchronized void unlock() {
if (lockBy == Thread.currentThread()) {
lockCount--;
if (lockCount == 0) {
isLocked = false;
notifyAll();
}
}
}
@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;
}
}
验证
public class Demo2 {
private MyReentrantLock lock = new MyReentrantLock();
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) {
Demo2 demo2 = new Demo2();
demo2.a();
}
}
运行后可以看到a,b都打印出来了,即实现了锁的重入。