Lock锁实现线程同步

转载自:https://www.cnblogs.com/jycboy/p/5623113.html
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("\t余额为: " + 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中释放更安全。

猜你喜欢

转载自blog.csdn.net/flower_csdn/article/details/79619849