• 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();
    				}
    			}
    		}
    	}
    }
    
  • 相关阅读:
    Python-Image 基本的图像处理操作
    剪枝
    poj1182(食物链)续
    HLG2035广搜
    HLG2040二叉树遍历已知前中,求后
    先序,中序,后序,已知两者求第三者
    C++中new的解说
    僵尸进程
    HLG2062(make,heap问题)
    make_head,,,pop_head,,,push_head,,,sort_head..
  • 原文地址:https://www.cnblogs.com/wgty/p/12810478.html
Copyright © 2020-2023  润新知