Java线程同步Lock同步锁代码示例

 更新时间:2017年11月14日 09:03:40   作者:超超boy  
这篇文章主要介绍了Java线程同步Lock同步锁代码示例,首先介绍了Java线程同步的原理,然后对lock同步锁作了简要阐述,分享了代码示例,具有一定参考价值,需要的朋友可以了解下。

java线程同步原理

java会为每个object对象分配一个monitor,当某个对象的同步方法(synchronizedmethods)被多个线程调用时,该对象的monitor将负责处理这些访问的并发独占要求。

当一个线程调用一个对象的同步方法时,JVM会检查该对象的monitor。如果monitor没有被占用,那么这个线程就得到了monitor的占有权,可以继续执行该对象的同步方法;如果monitor被其他线程所占用,那么该线程将被挂起,直到monitor被释放。

当线程退出同步方法调用时,该线程会释放monitor,这将允许其他等待的线程获得monitor以使对同步方法的调用执行下去。

注意:Java对象的monitor机制和传统的临界检查代码区技术不一样。java的一个同步方法并不意味着同时只有一个线程独占执行,但临界检查代码区技术确实会保证同步方法在一个时刻只被一个线程独占执行。Java的monitor机制的准确含义是:任何时刻,对一个指定object对象的某同步方法只能由一个线程来调用。

java对象的monitor是跟随object实例来使用的,而不是跟随程序代码。两个线程可以同时执行相同的同步方法,比如:一个类的同步方法是xMethod(),有a,b两个对象实例,一个线程执行a.xMethod(),另一个线程执行b.xMethod().互不冲突。

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中释放更安全。

总结

以上就是本文关于Java线程同步Lock同步锁代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:

创建并运行一个java线程方法介绍

Java编程之多线程死锁与线程间通信简单实现代码

Java多线程编程小实例模拟停车场系统

有什么问题可以随时留言,小编会及时回复大家的。感谢朋友们对本站的支持!

相关文章

  • hibernate框架环境搭建具体步骤(介绍)

    hibernate框架环境搭建具体步骤(介绍)

    下面小编就为大家带来一篇hibernate框架环境搭建具体步骤(介绍)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • 关于SpringCloud的Bus消息总线图文详解

    关于SpringCloud的Bus消息总线图文详解

    这篇文章主要介绍了关于SpringCloud的Bus消息总线图文详解,Spring Cloud Bus是用来将分布式系统的节点与轻量级消息系统链接起来的框架,它整合了Java的事件处理机制和消息中间件的功能,需要的朋友可以参考下
    2023-05-05
  • java线程之Happens before规则案例详解

    java线程之Happens before规则案例详解

    这篇文章主要为大家介绍了java线程之Happens-before规则,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪<BR>
    2022-08-08
  • idea项目实现移除和添加git

    idea项目实现移除和添加git

    本文指导读者如何从官网下载并安装Git,以及在IDEA中配置Git的详细步骤,首先,用户需访问Git官方网站下载适合自己操作系统的Git版本并完成安装,接着,在IDEA中通过设置找到git.exe文件以配置Gi
    2024-10-10
  • Java方法重载Overload原理及使用解析

    Java方法重载Overload原理及使用解析

    这篇文章主要介绍了Java方法重载Overload原理及使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • java8 streamList转换使用详解

    java8 streamList转换使用详解

    这篇文章主要介绍了java8 streamList转换使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • java中的Reference和引用类型实例精讲

    java中的Reference和引用类型实例精讲

    这篇文章主要为大家介绍了java中的Reference和引用类型示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Kotlin + Spring Boot 请求参数验证的代码实例

    Kotlin + Spring Boot 请求参数验证的代码实例

    本篇文章主要介绍了Kotlin + Spring Boot 请求参数验证的代码实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • spring-integration连接MQTT全过程

    spring-integration连接MQTT全过程

    这篇文章主要介绍了spring-integration连接MQTT全过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • 解决java 分割字符串成数组时,小圆点不能直接进行分割的问题

    解决java 分割字符串成数组时,小圆点不能直接进行分割的问题

    这篇文章主要介绍了解决java 分割字符串成数组时,小圆点不能直接进行分割的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12

最新评论