Lock锁---实现安全卖票

  上一篇文章中:线程安全问题经典案例—卖票,我们使用了synchronized同步代码块来实现了线程安全,这篇文章我们使用Lock锁来实现同样的效果。

Lock锁介绍

Lock锁是java jdk1.5版本之后添加一个处理线程安全问题的接口。相比较synchronized而言,更加灵活,因为它不在局限于一个代码块,实现了一些synchronized同步锁所不能实现的功能。

JDK1.6 API文档
在这里插入图片描述

卖票案例代码实现
public class RunnableImpl implements Runnable {

	//给一个共享资源
	private int ticket = 100;

	//new 一个Lock锁的实现类对象

	Lock lock = new ReentrantLock();

	//指定线程所要执行的任务(卖票)
	@Override
	public void run() {
		while (true) {
		//在可能会出现线程安全问题的地方 显式的调用lock中的.lock()方法进行加锁
			lock.lock();
			if (ticket > 0) {
				System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张电影票");
				//为了卖票出错的情况更加明显,我们让线程等待100ms
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				--ticket;
			}
			//在代码执行结束的地方,显式的调用lock对象中的.unlock()方法,释放锁资源
			lock.unlock();
		}
	}
}
public class FileTest {

	public static void main(String[] args) {

		//思考:为什么这里只new 了一个Runnable的对象传到了三个线程种?
		RunnableImpl runnable = new RunnableImpl();

		//new 三个线程出来模三个窗口,为了符合情景,我们为线程设置一个线程名
		Thread thread1 = new Thread(runnable);
		thread1.setName("窗口1");

		Thread thread2 = new Thread(runnable);
		thread2.setName("窗口2");

		Thread thread3 = new Thread(runnable);
		thread3.setName("窗口3");

		thread1.start();
		thread2.start();
		thread3.start();

	}
}

启动项目之后,发现直接从100张电影票顺序卖出去了,说明使用Lock锁成功解决了线程安全问题。
在这里插入图片描述

synchronized和Lock比较

synchronized:

  1. 优势:
       此种方式最大的好处就是不需要显式的去加锁释放锁,线程A执行到同步代码块的地方,自动判断synchronized是否有对象锁,有则进入同步代码块中执行任务,没有对象锁就说明此刻有其他线程B正在执行此同步代码块,线程A则进入阻塞状态。

  2. 劣势:
      相比较Lock而言,synchronized同步锁比较死板,不够灵活,因为synchronized一般使用在同步代码块或者同步方法上,都可以看作是一个块状结构,也就是强制要求了所有的获取锁和释放锁都必须在一个块结构中。但是Lock就没有此种困扰。

Lock:
  Lock的优势不再赘述,这里就强调一点:使用Lock一定要注意不要忘记添加lock.unlock()显示的释放锁资源,在项目开发的过程中,我们一般将它放到try()catch{……}finnly{lock.unlock()}的finnly{}代码块中,也就是说,无论try()代码块中有没有捕获到异常,该锁始终会被释放掉。

public class RunnableImpl implements Runnable {

	//给一个共享资源
	private int ticket = 100;

	//new 一个Lock锁的实现类对象

	Lock lock = new ReentrantLock();

	//指定线程所要执行的任务(卖票)
	@Override
	public void run() {
		while (true) {
			lock.lock();
			if (ticket > 0) {
				try {
					System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张电影票");
					//为了卖票出错的情况更加明显,我们让线程等待100ms
					--ticket;
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					lock.unlock();
				}
			}
		}
	}
}
原文地址:https://www.cnblogs.com/wgty/p/12810478.html