线程的Lock锁
虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁, JDK5以后提供了一个新的锁对象Lock
Lock是接口,该接口在java.util.concurrent.locks包下
该接口实现提供了比使用synchronized方法和语句可以获得的更广泛的锁定操作,该接口提供了两个方法,如下
方法 | 作用 |
---|---|
lock() | 获得锁 |
unlock() | 释放锁 |
Lock是一个接口,不能直接实例化即不能直接创建对象,需要通过Lock接口的实现类,Lock的实现类如下: ReentrantLock、ReentrantReadWriteLock.ReadLock、ReentrantReadWriteLock.WriteLock
我们一般使用ReentrantLock来实例化,ReentrantLock类的无参构造方法:ReentrantLock() 创建一个ReentrantLock的实例
线程Lock锁的练习
xxxxxxxxxx
package ch21;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class a_15_1SellTicket implements Runnable{
private int tickets = 100;
private Lock lock = new ReentrantLock();//Lock不能直接创建对象,通过右边的实现类对象ReentrantLock来创建Lock对象
/*public void run() {
while(true){
//第一次代码演示,这里还没有使用同步,即还没有加锁
//第二次代码演示,我们在下面一行加上Lock锁
try {//也可以把这里的try...catch写到if里面。但是写在外面,输出的效果会比较明显
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
if(tickets>0){
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
tickets--;
}
lock.unlock();
//由于没有加锁,我们的程序出现了重复票和负票等数据安全。我们用这节课的Lock锁解决数据安全
//首先在最上面创建Lock锁对象,然后在while循环里使用Lock的方法即lock()获得锁、unlock()释放锁
//原理:把多条语句共享数据的代码用Lock锁锁起来
//最后去操作类运行一下,发现数据安全的问题就解决了
}
}*/
//上面那种写法的弊端:一旦前面if语句出现问题,则后面的释放锁语句就不会执行,导致占用系统资源
//-------------------------------------------------------------------------------------------------------
//实际开发中我们的写法如下,注:上面和下面的两部分其实都可以,使用一部分即可,另一部分注释。下面这种写法考虑更全
public void run() {
while(true){
try{
try {//也可以把这里的try...catch写到if里面。但是写在外面,输出的效果会比较明显
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
if(tickets>0){
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
tickets--;
}
}finally {
lock.unlock();
}
}
//这种写法的优点:如果我们if代码出问题了,最后也会去释放锁
}
}
xxxxxxxxxx
package ch21;
public class a_15_2测试 {
public static void main(String[] args) {
a_15_1SellTicket st = new a_15_1SellTicket();
Thread t1 = new Thread(st,"线程1");
Thread t2 = new Thread(st,"线程2");
Thread t3 = new Thread(st,"线程3");
t1.start();
t2.start();
t3.start();
}
}