由于synchronized关键字锁对象的添加与释放我们并不明确,java为我们提供了一个Lock接口
Lock接口源自JDK5,其有三个直接实现类,分别是 :
ReentrantLock,ReentrantReadWriteLock.ReadLock,ReentrantReadWriteLock.WriteLock
其中后两个是ReentrantReadWriteLock的嵌套类

方法

1
2
3
4
5
6
7
void lock();//获取锁
void unlock();//释放锁
void lockInterruptibly();//当前线程未中断则获取锁
Condition newCondition();//返回此Lock实例的新实例
boolean tryLock();//仅在调用时锁为空闲状态才获取锁
boolean tryLock(long time, TimeUnit unit);//若锁在给定时间空闲且当前线程未中断,获取锁
//TimeUnit为参数的时间单位
简单案例 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Runnable ticket = new Runnable() {
private int ticket = 100;
Lock lock = new ReentrantLock();
@Override
public void run() {
while (ticket > 0){
lock.lock();
if (ticket > 0)
System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket-- + "张票!");
lock.unlock();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread thread1 = new Thread(ticket,"窗口1");
Thread thread2 = new Thread(ticket,"窗口2");
Thread thread3 = new Thread(ticket,"窗口3");
thread1.start();
thread2.start();
thread3.start();
执行结果如下 :

出现异常锁资源释放问题

由于需要程序调用unlock()方法来释放锁资源,那么如果在释放之前出现异常呢?
改动如下 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if (ticket > 0)
System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket-- + "张票!");
if (Thread.currentThread().getName().equals("窗口1") && ticket < 80)
System.out.println(10 / 0);
lock.unlock();
...
thread1.start();
thread2.start();
thread3.start();
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread1.isAlive());
可以看到,由于"窗口1"被异常终止且没有释放锁,其他两个线程一直在等待锁
结果如下 : 

使用Lock实现类做同步的处理,一定要记得处理锁对象的释放问题
用try-catch-finally处理释放问题
改进如下 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
while (ticket > 0){
try {
lock.lock();
if (ticket > 0)
System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket-- + "张票!");
if (Thread.currentThread().getName().equals("窗口1") && ticket < 80)
System.out.println(10 / 0);
} catch (Exception e) {
e.printStackTrace();
break;
}finally {
lock.unlock();
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
执行结果如下 :