线程的Lock锁
虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁, JDK5以后提供了一个新的锁对象Lock
Lock是接口,该接口在java.util.concurrent.locks包下
该接口实现提供了比使用synchronized方法和语句可以获得的更广泛的锁定操作,该接口提供了两个方法,如下
| 方法 | 作用 |
|---|---|
| lock() | 获得锁 |
| unlock() | 释放锁 |
Lock是一个接口,不能直接实例化即不能直接创建对象,需要通过Lock接口的实现类,Lock的实现类如下: ReentrantLock、ReentrantReadWriteLock.ReadLock、ReentrantReadWriteLock.WriteLock
我们一般使用ReentrantLock来实例化,ReentrantLock类的无参构造方法:ReentrantLock() 创建一个ReentrantLock的实例
线程Lock锁的练习
xxxxxxxxxxpackage 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代码出问题了,最后也会去释放锁 }
}xxxxxxxxxxpackage 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();
}}