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多线程编程小实例模拟停车场系统

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

相关文章

  • java17日期周期格式化处理方案

    java17日期周期格式化处理方案

    Java17引入了新的日期时间格式化模式B,用于表示一天中的时间段,如上午、下午、晚上等,该模式根据CLDR定义,在不同语言环境下,该模式的输出结果会有所不同,本文给大家介绍java17日期周期格式化处理方案,感兴趣的朋友跟随小编一起看看吧
    2025-01-01
  • 使用Java读取Word文件的简单例子分享

    使用Java读取Word文件的简单例子分享

    这篇文章主要介绍了使用Java读取Word文件的简单例子分享,包括读取word文件的表格数据的示例,需要的朋友可以参考下
    2015-10-10
  • 基于SpringBoot Mock单元测试详解

    基于SpringBoot Mock单元测试详解

    这篇文章主要介绍了基于SpringBoot Mock单元测试详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java输入数据的知识点整理

    Java输入数据的知识点整理

    在本篇文章里小编给大家整理的是关于Java如何输入数据的相关知识点内容,有兴趣的朋友们学习参考下。
    2020-01-01
  • Java基础之删除文本文件中特定行的内容

    Java基础之删除文本文件中特定行的内容

    这篇文章主要介绍了Java基础之删除文本文件中特定行的内容,文中有非常详细的代码示例,对正在学习java基础的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • spring boot2结合mybatis增删改查的实现

    spring boot2结合mybatis增删改查的实现

    这篇文章主要给大家介绍了关于spring boot2结合mybatis增删改查的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用spring boot2具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-09-09
  • JVM:你知道为什么对象一定在堆中分配吗

    JVM:你知道为什么对象一定在堆中分配吗

    这篇文章主要介绍了jvm对象的创建和分配的相关资料,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下,希望能够给你带来帮助
    2021-08-08
  • Java MongoDB数据库连接方法梳理

    Java MongoDB数据库连接方法梳理

    MongoDB作为一种介于关系型数据库和非关系型数据库之间的产品,它可以提供可扩展的高性能的数据存储解决方案,近些年来受到了开发者的喜爱
    2022-08-08
  • SpringBoot如何启动自动加载自定义模块yml文件(PropertySourceFactory)

    SpringBoot如何启动自动加载自定义模块yml文件(PropertySourceFactory)

    这篇文章主要介绍了SpringBoot如何启动自动加载自定义模块yml文件(PropertySourceFactory),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • 关于@Value注解取不到值的几种情况

    关于@Value注解取不到值的几种情况

    这篇文章主要介绍了关于@Value注解取不到值的几种情况,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11

最新评论