JDK5中Lock锁的使用
虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock
Lock
•void lock()
•void unlock()
实现类:ReentrantLock
使用Lock需要显式的加锁和解锁
- 解锁操作需要放在finally块里,若不放在finally块中,若上面的代码抛出异常,那么会造成锁无法释放,可能会造成死锁问题
- 另外,获取锁的操作不能放在try块里,因为Lock是可重入锁(上一篇博客已经讲述了可重入锁和不可重入锁的问题),如果外层也已经调用lock()方法,而里层因为调用lock()抛出异常然后调用unlock,外层无法知晓,导致外层代码无法正确同步。
还是拿卖电影票的列子来说一下Lock锁的使用,代码如下:
自定义线程类:
package m8d8;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SellTickets implements Runnable{
private int amount = 100;
Lock lock = new ReentrantLock();
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
//加锁
lock.lock();
try {
if(amount>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+(amount--)+"张票");
}
}finally {
//释放锁
lock.unlock();
}
}
}
}
测试类:
package m8d8;
public class SellTicketsDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
SellTickets sellTickets = new SellTickets();
Thread threadA = new Thread(sellTickets, "窗口A");
Thread threadB = new Thread(sellTickets, "窗口B");
Thread threadC = new Thread(sellTickets, "窗口C");
threadA.start();
threadB.start();
threadC.start();
}
}
死锁问题
同步弊端
•效率低
•如果出现了同步嵌套,就容易产生死锁问题
死锁问题及其代码
•是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象
•同步代码块的嵌套案例
下面是同步代码块嵌套造成死锁问题的案例:
自定义线程类:
package m8d9;
public class TextDemo extends Thread{
private boolean isLock = false;
private static final Object objA = new Object();
private static final Object objB = new Object();
public TextDemo(){
}
public TextDemo(boolean isLock) {
this.isLock = isLock;
}
@Override
public void run() {
// TODO Auto-generated method stub
if(isLock) {
synchronized (objA) {
System.out.println("if objA");
synchronized (objB) {
System.out.println("if objB");
}
}
}else {
synchronized (objB) {
System.out.println("else objB");
synchronized (objA) {
System.out.println("else objA");
}
}
}
}
}
测试类:
package m8d9;
public class Demo {
public static void main(String[] args) {
TextDemo demo = new TextDemo(false);
TextDemo demo2 = new TextDemo(true);
demo.start();
demo2.start();
}
}
运行结果:
分析:当demo2抢到线程的执行权的时候,执行输出:if objA(这时候还没有释放锁A),之后demo抢到了执行权执行了else objB(这时候还没有释放锁B),假设之后是demo线程抢到执行权,他在等锁A的释放才能继续执行,所以只能等待,但是的demo2也在等待锁B的释放继续执行,这就变成两个线程互相等待,造成了死锁问题