• Lock同步锁--线程同步


    Lock-同步锁

    Lock是java5提供的一个强大的线程同步机制--通过显示定义同步锁对象来实现同步。Lock可以显示的加锁、解锁。每次只能有一个线程对lock对象加锁。

    Lock有ReadLock、WriteLock、ReentrantLock(可重入锁)

    常用的就是ReentrantLock。代码如下:

    代码逻辑:Account账户类,实现取钱的同步方法、DrawThread取钱的线程

    Account:

    package lock.reentrantlock2;
    import java.util.concurrent.locks.*;
    
    /**
     *账户类,需保持同步
     */
    public class Account
    {
    	//定义锁对象
    	private final ReentrantLock lock = new ReentrantLock();
    	private String accountNo;
    	private double balance;
    
    
    	public Account(){}
    
    	public Account(String accountNo , double balance)
    	{
    		this.accountNo = accountNo;
    		this.balance = balance;
    	}
    
    	public void setAccountNo(String accountNo)
    	{
    		this.accountNo = accountNo;
    	}
    	public String getAccountNo()
    	{
    		 return this.accountNo;
    	}
    
    	public double getBalance()
    	{
    		 return this.balance;
    	}
    	public void draw(double drawAmount)
    	{
    		lock.lock();
    		try
    		{
    			//账户余额大于取钱数目
    			if (balance >= drawAmount)
    			{
    				//吐出钞票
    				System.out.println(Thread.currentThread().getName() + 
    					"取钱成功!吐出钞票:" + drawAmount);
    				try
    				{
    					Thread.sleep(1);			
    				}
    				catch (InterruptedException ex)
    				{
    					ex.printStackTrace();
    				}
    				//修改余额
    				balance -= drawAmount;
    				System.out.println("	余额为: " + balance);
    			}
    			else
    			{
    				System.out.println(Thread.currentThread().getName() +
    					"取钱失败!余额不足!");
    			}			
    		}
    		finally
    		{
    			lock.unlock();
    		}
    	}
    
    	public int hashCode()
    	{
    		return accountNo.hashCode();
    	}
    	public boolean equals(Object obj)
    	{
    		if (obj != null && obj.getClass() == Account.class)
    		{
    			Account target = (Account)obj;
    			return target.getAccountNo().equals(accountNo);
    		}
    		return false;
    	}
    }
    

      DrawThread:

    package lock.reentrantlock2;
    
    /**
     * 调用account取钱
     * 
     */
    
    public class DrawThread extends Thread
    {
    	//模拟用户账户
    	private Account account;
    	//当前取钱线程所希望取的钱数
    	private double drawAmount;
    
    	public DrawThread(String name , Account account , 
    		double drawAmount)
    	{
    		super(name);
    		this.account = account;
    		this.drawAmount = drawAmount;
    	}
    
    	//当多条线程修改同一个共享数据时,将涉及到数据安全问题。
    	public void run()
    	{
    		account.draw(drawAmount);
    	}
    }
    

      TestDraw:

    package lock.reentrantlock2;
    
    /**
     
     */
    public class TestDraw
    {
        public static void main(String[] args) 
        {
    		//创建一个账户
    		Account acct = new Account("1234567" , 1000);
    		//模拟两个线程对同一个账户取钱
    		new DrawThread("甲" , acct , 800).start();
    		new DrawThread("乙" , acct , 800).start();
        }
    }
     
    

      运行结果:

    甲取钱成功!吐出钞票:800.0
    余额为: 200.0
    乙取钱失败!余额不足!

    使用Lock同步与同步方法很相似,都是“加锁--修改公共变量--释放锁”的模式,代码很容易看懂。两个线程对应一个Account对象,保证了两个线程对应一个lock对象,保证了同一时刻只有一个线程进入临界区。Lock还包含太容易Lock(),以及试图获取可中断锁的lockInterruptibly(),获取超时失效锁的tryLock(long,TimeUnit)等方法。

      ReentrantLock锁具有可重入性可以对已被加锁的ReentrantLock锁再次加锁,线程每次调用lock()加锁后,必须显示的调用unlock来释放锁,有几个lock就对应几个unlock。还有把unlock放在finally代码块中,Lock在发生异常时也是不释放锁的,所以在finally中释放更安全。

    只是对Lock简单说明了下,为下一篇线程通信打基础。

  • 相关阅读:
    修改Chrome设置伪装成手机M站
    使用Chrome浏览器自动将文件下载到指定路径
    操作HTML5存储对象
    在HTML5的画布元素上进行绘画操作
    测试HTML5语言实现的视频播放器
    封装操作表格的公用类
    测试过程中发生异常或断言失败时进行屏幕截图
    浏览器中新开标签页(Tab)
    高亮显示正在操作的页面元素
    精确比较页面截图图片
  • 原文地址:https://www.cnblogs.com/jycboy/p/5623113.html
Copyright © 2020-2023  润新知